diff options
Diffstat (limited to 'src/trace/filterset.cpp')
-rw-r--r-- | src/trace/filterset.cpp | 428 |
1 files changed, 428 insertions, 0 deletions
diff --git a/src/trace/filterset.cpp b/src/trace/filterset.cpp new file mode 100644 index 0000000..331d4e3 --- /dev/null +++ b/src/trace/filterset.cpp @@ -0,0 +1,428 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Some filters for Potrace in Inkscape + * + * Authors: + * Bob Jamison <rjamison@titan.com> + * Stéphane Gimenez <dev@gim.name> + * + * Copyright (C) 2004-2006 Authors + * + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ + +#include <cstdio> +#include <cstdlib> + +#include "imagemap-gdk.h" +#include "filterset.h" +#include "quantize.h" + +/*######################################################################### +### G A U S S I A N (smoothing) +#########################################################################*/ + +/** + * + */ +static int gaussMatrix[] = +{ + 2, 4, 5, 4, 2, + 4, 9, 12, 9, 4, + 5, 12, 15, 12, 5, + 4, 9, 12, 9, 4, + 2, 4, 5, 4, 2 +}; + + +/** + * + */ +GrayMap *grayMapGaussian(GrayMap *me) +{ + int width = me->width; + int height = me->height; + int firstX = 2; + int lastX = width-3; + int firstY = 2; + int lastY = height-3; + + GrayMap *newGm = GrayMapCreate(width, height); + if (!newGm) + return nullptr; + + for (int y = 0 ; y<height ; y++) + { + for (int x = 0 ; x<width ; x++) + { + /* image boundaries */ + if (x<firstX || x>lastX || y<firstY || y>lastY) + { + newGm->setPixel(newGm, x, y, me->getPixel(me, x, y)); + continue; + } + + /* all other pixels */ + int gaussIndex = 0; + unsigned long sum = 0; + for (int i= y-2 ; i<=y+2 ; i++) + { + for (int j= x-2; j<=x+2 ; j++) + { + int weight = gaussMatrix[gaussIndex++]; + sum += me->getPixel(me, j, i) * weight; + } + } + sum /= 159; + newGm->setPixel(newGm, x, y, sum); + } + } + + return newGm; +} + + + + + +/** + * + */ +RgbMap *rgbMapGaussian(RgbMap *me) +{ + int width = me->width; + int height = me->height; + int firstX = 2; + int lastX = width-3; + int firstY = 2; + int lastY = height-3; + + RgbMap *newGm = RgbMapCreate(width, height); + if (!newGm) + return nullptr; + + for (int y = 0 ; y<height ; y++) + { + for (int x = 0 ; x<width ; x++) + { + /* image boundaries */ + if (x<firstX || x>lastX || y<firstY || y>lastY) + { + newGm->setPixelRGB(newGm, x, y, me->getPixel(me, x, y)); + continue; + } + + /* all other pixels */ + int gaussIndex = 0; + int sumR = 0; + int sumG = 0; + int sumB = 0; + for (int i= y-2 ; i<=y+2 ; i++) + { + for (int j= x-2; j<=x+2 ; j++) + { + int weight = gaussMatrix[gaussIndex++]; + RGB rgb = me->getPixel(me, j, i); + sumR += weight * (int)rgb.r; + sumG += weight * (int)rgb.g; + sumB += weight * (int)rgb.b; + } + } + RGB rout; + rout.r = ( sumR / 159 ) & 0xff; + rout.g = ( sumG / 159 ) & 0xff; + rout.b = ( sumB / 159 ) & 0xff; + newGm->setPixelRGB(newGm, x, y, rout); + } + } + + return newGm; + +} + + + + +/*######################################################################### +### C A N N Y E D G E D E T E C T I O N +#########################################################################*/ + + +static int sobelX[] = +{ + -1, 0, 1 , + -2, 0, 2 , + -1, 0, 1 +}; + +static int sobelY[] = +{ + 1, 2, 1 , + 0, 0, 0 , + -1, -2, -1 +}; + + + +/** + * Perform Sobel convolution on a GrayMap + */ +static GrayMap *grayMapSobel(GrayMap *gm, + double dLowThreshold, double dHighThreshold) +{ + int width = gm->width; + int height = gm->height; + int firstX = 1; + int lastX = width-2; + int firstY = 1; + int lastY = height-2; + + GrayMap *newGm = GrayMapCreate(width, height); + if (!newGm) + return nullptr; + + for (int y = 0 ; y<height ; y++) + { + for (int x = 0 ; x<width ; x++) + { + unsigned long sum = 0; + /* image boundaries */ + if (x<firstX || x>lastX || y<firstY || y>lastY) + { + sum = 0; + } + else + { + /* ### SOBEL FILTERING #### */ + long sumX = 0; + long sumY = 0; + int sobelIndex = 0; + for (int i= y-1 ; i<=y+1 ; i++) + { + for (int j= x-1; j<=x+1 ; j++) + { + sumX += gm->getPixel(gm, j, i) * + sobelX[sobelIndex++]; + } + } + + sobelIndex = 0; + for (int i= y-1 ; i<=y+1 ; i++) + { + for (int j= x-1; j<=x+1 ; j++) + { + sumY += gm->getPixel(gm, j, i) * + sobelY[sobelIndex++]; + } + } + /*### GET VALUE ### */ + sum = abs(sumX) + abs(sumY); + + if (sum > 765) + sum = 765; + +#if 0 + /*### GET ORIENTATION (slow, pedantic way) ### */ + double orient = 0.0; + if (sumX==0) + { + if (sumY==0) + orient = 0.0; + else if (sumY<0) + { + sumY = -sumY; + orient = 90.0; + } + else + orient = 90.0; + } + else + { + orient = 57.295779515 * atan2( ((double)sumY),((double)sumX) ); + if (orient < 0.0) + orient += 180.0; + } + + /*### GET EDGE DIRECTION ### */ + int edgeDirection = 0; + if (orient < 22.5) + edgeDirection = 0; + else if (orient < 67.5) + edgeDirection = 45; + else if (orient < 112.5) + edgeDirection = 90; + else if (orient < 157.5) + edgeDirection = 135; +#else + /*### GET EDGE DIRECTION (fast way) ### */ + int edgeDirection = 0; /*x,y=0*/ + if (sumX==0) + { + if (sumY!=0) + edgeDirection = 90; + } + else + { + /*long slope = sumY*1024/sumX;*/ + long slope = (sumY << 10)/sumX; + if (slope > 2472 || slope< -2472) /*tan(67.5)*1024*/ + edgeDirection = 90; + else if (slope > 414) /*tan(22.5)*1024*/ + edgeDirection = 45; + else if (slope < -414) /*-tan(22.5)*1024*/ + edgeDirection = 135; + } + +#endif + /* printf("%ld %ld %f %d\n", sumX, sumY, orient, edgeDirection); */ + + /*### Get two adjacent pixels in edge direction ### */ + unsigned long leftPixel; + unsigned long rightPixel; + if (edgeDirection == 0) + { + leftPixel = gm->getPixel(gm, x-1, y); + rightPixel = gm->getPixel(gm, x+1, y); + } + else if (edgeDirection == 45) + { + leftPixel = gm->getPixel(gm, x-1, y+1); + rightPixel = gm->getPixel(gm, x+1, y-1); + } + else if (edgeDirection == 90) + { + leftPixel = gm->getPixel(gm, x, y-1); + rightPixel = gm->getPixel(gm, x, y+1); + } + else /*135 */ + { + leftPixel = gm->getPixel(gm, x-1, y-1); + rightPixel = gm->getPixel(gm, x+1, y+1); + } + + /*### Compare current value to adjacent pixels ### */ + /*### if less that either, suppress it ### */ + if (sum < leftPixel || sum < rightPixel) + sum = 0; + else + { + unsigned long highThreshold = + (unsigned long)(dHighThreshold * 765.0); + unsigned long lowThreshold = + (unsigned long)(dLowThreshold * 765.0); + if (sum >= highThreshold) + sum = 765; /* EDGE. 3*255 this needs to be settable */ + else if (sum < lowThreshold) + sum = 0; /* NONEDGE */ + else + { + if ( gm->getPixel(gm, x-1, y-1)> highThreshold || + gm->getPixel(gm, x , y-1)> highThreshold || + gm->getPixel(gm, x+1, y-1)> highThreshold || + gm->getPixel(gm, x-1, y )> highThreshold || + gm->getPixel(gm, x+1, y )> highThreshold || + gm->getPixel(gm, x-1, y+1)> highThreshold || + gm->getPixel(gm, x , y+1)> highThreshold || + gm->getPixel(gm, x+1, y+1)> highThreshold) + sum = 765; /* EDGE fix me too */ + else + sum = 0; /* NONEDGE */ + } + } + + + }/* else */ + if (sum==0) /* invert light & dark */ + sum = 765; + else + sum = 0; + newGm->setPixel(newGm, x, y, sum); + }/* for (x) */ + }/* for (y) */ + + return newGm; +} + + + + + +/** + * + */ +GrayMap * +grayMapCanny(GrayMap *gm, double lowThreshold, double highThreshold) +{ + if (!gm) + return nullptr; + + GrayMap *cannyGm = grayMapSobel(gm, lowThreshold, highThreshold); + if (!cannyGm) + return nullptr; + /*cannyGm->writePPM(cannyGm, "canny.ppm");*/ + + return cannyGm; +} + + + +/*######################################################################### +### Q U A N T I Z A T I O N +#########################################################################*/ + +/** + * Experimental. Work on this later + */ +GrayMap *quantizeBand(RgbMap *rgbMap, int nrColors) +{ + + RgbMap *gaussMap = rgbMapGaussian(rgbMap); + if (!gaussMap) + return nullptr; + //gaussMap->writePPM(gaussMap, "rgbgauss.ppm"); + + IndexedMap *qMap = rgbMapQuantize(gaussMap, nrColors); + gaussMap->destroy(gaussMap); + if (!qMap) + return nullptr; + //qMap->writePPM(qMap, "rgbquant.ppm"); + + GrayMap *gm = GrayMapCreate(rgbMap->width, rgbMap->height); + if (!gm) + return nullptr; + + // RGB is quantized. There should now be a small set of (R+G+B) + for (int y=0 ; y<qMap->height ; y++) + { + for (int x=0 ; x<qMap->width ; x++) + { + RGB rgb = qMap->getPixelValue(qMap, x, y); + int sum = rgb.r + rgb.g + rgb.b; + if (sum & 1) + sum = 765; + else + sum = 0; + // printf("%d %d %d : %d\n", rgb.r, rgb.g, rgb.b, index); + gm->setPixel(gm, x, y, sum); + } + } + + qMap->destroy(qMap); + + return gm; +} + + +/*######################################################################### +### E N D O F F I L E +#########################################################################*/ + + + + + + + + + + |