/*
Code by lingib
Last update 12 Feb 2017
This software uses a 3x3 Sobel operator and threshold to detect the
outlines within an image. These outlines are then converted to gcode
for use with an Inkscape compatible plotter which assumes that the
(0,0) co-ordinate is at the lower left).
This code is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This software 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. If
not, see .
*/
PrintWriter output; //instantiate output
PImage src, sobel; //image work areas
// ----- trace() parameters
boolean recursionFlag; //3x3 matrix scan
boolean lastCommandG00 = false;
int lastX = 0;
int lastY = 0;
int recursionDepth; //maximum recursion recursionDepth ... stops stack overflow
// ----- sobel variables
int threshold = 80; //determines the amount of detail
float brightnessValue; //sobel value for center pixel
// ----- sobel horizontal matrix
int [][] sobel_x = {
{-1, 0, 1},
{-2, 0, 2},
{-1, 0, 1}
};
// ----- sobel vertical matrix
int [][] sobel_y = {
{-1, -2, -1},
{ 0, 0, 0},
{ 1, 2, 1}
};
// -------------------------------------
// setup
// -------------------------------------
void setup() {
size(467, 620); //match image size
src=loadImage("image.jpg");
src.filter(GRAY); //make image monochrome
src.loadPixels(); //load src pixels[] array
sobel = createImage(width, height, RGB);
sobel.loadPixels(); //load sobel pixels[] array
sobel.filter(INVERT); //change background to white
// ----- find edges
/* run sobel matrix center over the image */
for (int x = 1; x < width-1; x++) {
for (int y = 1; y < height-1; y++) {
// ----- center pixel location
int pixel = x + y*width;
// ----- center pixel brightness
brightnessValue = pixelBrightness(x, y, sobel_x, sobel_y, src);
// ----- create sobel image
if (brightnessValue > threshold) { //threshold value determines the detail
sobel.pixels[pixel] = color(0);
} else {
sobel.pixels[pixel] = color(255);
}
}
}
// ----- display sobel image
sobel.updatePixels(); //sobel pixels have changed
image(sobel, 0, 0); //black outline on white backgraound
// Create a new file in the sketch directory
output = createWriter("outline.ngc");
noLoop(); //draw() only runs once
}
// -------------------------------------
// main loop
// -------------------------------------
void draw() {
// ----- refresh pixels[] array
loadPixels();
// ----- move 3x3 matrix center over the image
for (int y=1; y 0)) {
recursionFlag = false; //routine will exit unless a zero is found
// ----- scan the matrix
for (int j = -1; j < 2; j++) { //vert scan
for (int i = -1; i < 2; i++) { //hor scan
// ----- location of the pixel being examined
int x = X+i;
int y = Y+j;
x = constrain(x, 1, width-1);
y = constrain(y, 1, height-1);
// ----- recursive trace if zero found
value = int(brightness(pixels[x + y*width]));
if (value == 0) {
recursionFlag = true; //zero found
trace(x, y);
} //end recursive trace
} //end hor scan
} //end vert scan
} //end while
}
// ----------------------------------
// pixel brightness
//-----------------------------------
float pixelBrightness(int x, int y, int[][] sobel_x, int[][] sobel_y, PImage src) {
// ----- matrix corner
int X = x-1;
int Y = y-1;
// ----- sobel gradients
float Gx = 0; //sobel X gradient
float Gy = 0; //sobel Y gradient
float G = 0; //sobel gradient
// ----- calculate brightness of the matrix center pixel
for (int i=0; i<3; i++) {
for (int j=0; j<3; j++) {
// ----- location of pixel being examined
int xloc = X+i;
int yloc = Y+j;
int loc = xloc + yloc*src.width;
// ----- calculate the brightness in each direction
Gx += brightness(src.pixels[loc]) * sobel_x[i][j];
Gy += brightness(src.pixels[loc]) * sobel_y[i][j];
}
}
// ----- calculate the total brightness
/*
"G" should be divided by eight, as the center pixel has eight
surrounding cells. Ignoring this gives us more precision when
using integer threshold values.
*/
G = sqrt(Gx*Gx + Gy*Gy);
return G;
}