/* 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; }