Code

Fix build failure
[inkscape.git] / src / trace / filterset.cpp
1 /*
2  * Some filters for Potrace in Inkscape
3  *
4  * Authors:
5  *   Bob Jamison <rjamison@titan.com>
6  *   Stéphane Gimenez <dev@gim.name>
7  *
8  * Copyright (C) 2004-2006 Authors
9  *
10  * Released under GNU GPL, read the file 'COPYING' for more information
11  */
13 #include <cstdio>
14 #include <stdlib.h>
16 #include "imagemap-gdk.h"
17 #include "filterset.h"
18 #include "quantize.h"
20 /*#########################################################################
21 ### G A U S S I A N  (smoothing)
22 #########################################################################*/
24 /**
25  *
26  */
27 static int gaussMatrix[] =
28 {
29      2,  4,  5,  4, 2,
30      4,  9, 12,  9, 4,
31      5, 12, 15, 12, 5,
32      4,  9, 12,  9, 4,
33      2,  4,  5,  4, 2
34 };
37 /**
38  *
39  */
40 GrayMap *grayMapGaussian(GrayMap *me)
41 {
42     int width  = me->width;
43     int height = me->height;
44     int firstX = 2;
45     int lastX  = width-3;
46     int firstY = 2;
47     int lastY  = height-3;
49     GrayMap *newGm = GrayMapCreate(width, height);
50     if (!newGm)
51         return NULL;
53     for (int y = 0 ; y<height ; y++)
54         {
55         for (int x = 0 ; x<width ; x++)
56             {
57             /* image boundaries */
58             if (x<firstX || x>lastX || y<firstY || y>lastY)
59                 {
60                 newGm->setPixel(newGm, x, y, me->getPixel(me, x, y));
61                 continue;
62                 }
64             /* all other pixels */
65             int gaussIndex = 0;
66             unsigned long sum = 0;
67             for (int i= y-2 ; i<=y+2 ; i++)
68                 {
69                 for (int j= x-2; j<=x+2 ; j++)
70                     {
71                     int weight = gaussMatrix[gaussIndex++];
72                     sum += me->getPixel(me, j, i) * weight;
73                     }
74                 }
75             sum /= 159;
76             newGm->setPixel(newGm, x, y, sum);
77             }
78         }
80     return newGm;
81 }
87 /**
88  *
89  */
90 RgbMap *rgbMapGaussian(RgbMap *me)
91 {
92     int width  = me->width;
93     int height = me->height;
94     int firstX = 2;
95     int lastX  = width-3;
96     int firstY = 2;
97     int lastY  = height-3;
99     RgbMap *newGm = RgbMapCreate(width, height);
100     if (!newGm)
101         return NULL;
103     for (int y = 0 ; y<height ; y++)
104         {
105         for (int x = 0 ; x<width ; x++)
106             {
107             /* image boundaries */
108             if (x<firstX || x>lastX || y<firstY || y>lastY)
109                 {
110                 newGm->setPixelRGB(newGm, x, y, me->getPixel(me, x, y));
111                 continue;
112                 }
114             /* all other pixels */
115             int gaussIndex = 0;
116             int sumR       = 0;
117             int sumG       = 0;
118             int sumB       = 0;
119             for (int i= y-2 ; i<=y+2 ; i++)
120                 {
121                 for (int j= x-2; j<=x+2 ; j++)
122                     {
123                     int weight = gaussMatrix[gaussIndex++];
124                     RGB rgb = me->getPixel(me, j, i);
125                     sumR += weight * (int)rgb.r;
126                     sumG += weight * (int)rgb.g;
127                     sumB += weight * (int)rgb.b;
128                     }
129                 }
130             RGB rout;
131             rout.r = ( sumR / 159 ) & 0xff;
132             rout.g = ( sumG / 159 ) & 0xff;
133             rout.b = ( sumB / 159 ) & 0xff;
134             newGm->setPixelRGB(newGm, x, y, rout);
135             }
136         }
138     return newGm;
145 /*#########################################################################
146 ### C A N N Y    E D G E    D E T E C T I O N
147 #########################################################################*/
150 static int sobelX[] =
152     -1,  0,  1 ,
153     -2,  0,  2 ,
154     -1,  0,  1 
155 };
157 static int sobelY[] =
159      1,  2,  1 ,
160      0,  0,  0 ,
161     -1, -2, -1 
162 };
166 /**
167  * Perform Sobel convolution on a GrayMap
168  */
169 static GrayMap *grayMapSobel(GrayMap *gm, 
170                double dLowThreshold, double dHighThreshold)
172     int width  = gm->width;
173     int height = gm->height;
174     int firstX = 1;
175     int lastX  = width-2;
176     int firstY = 1;
177     int lastY  = height-2;
179     GrayMap *newGm = GrayMapCreate(width, height);
180     if (!newGm)
181         return NULL;
183     for (int y = 0 ; y<height ; y++)
184         {
185         for (int x = 0 ; x<width ; x++)
186             {
187             unsigned long sum = 0;
188             /* image boundaries */
189             if (x<firstX || x>lastX || y<firstY || y>lastY)
190                 {
191                 sum = 0;
192                 }
193             else
194                 {
195                 /* ### SOBEL FILTERING #### */
196                 long sumX = 0;
197                 long sumY = 0;
198                 int sobelIndex = 0;
199                 for (int i= y-1 ; i<=y+1 ; i++)
200                     {
201                     for (int j= x-1; j<=x+1 ; j++)
202                         {
203                         sumX += gm->getPixel(gm, j, i) * 
204                              sobelX[sobelIndex++];
205                         }
206                     }
208                 sobelIndex = 0;
209                 for (int i= y-1 ; i<=y+1 ; i++)
210                     {
211                     for (int j= x-1; j<=x+1 ; j++)
212                         {
213                         sumY += gm->getPixel(gm, j, i) * 
214                              sobelY[sobelIndex++];
215                         }
216                     }
217                 /*###  GET VALUE ### */
218                 sum = abs(sumX) + abs(sumY);
220                 if (sum > 765)
221                     sum = 765;
223 #if 0
224                 /*###  GET ORIENTATION (slow, pedantic way) ### */
225                 double orient = 0.0;
226                 if (sumX==0)
227                     {
228                     if (sumY==0)
229                         orient = 0.0;
230                     else if (sumY<0)
231                         {
232                         sumY = -sumY;
233                         orient = 90.0;
234                         }
235                     else
236                         orient = 90.0;
237                     }
238                 else
239                     {
240                     orient = 57.295779515 * atan2( ((double)sumY),((double)sumX) );
241                     if (orient < 0.0)
242                         orient += 180.0;
243                     }
245                 /*###  GET EDGE DIRECTION ### */
246                 int edgeDirection = 0;
247                 if (orient < 22.5)
248                     edgeDirection = 0;
249                 else if (orient < 67.5)
250                     edgeDirection = 45;
251                 else if (orient < 112.5)
252                     edgeDirection = 90;
253                 else if (orient < 157.5)
254                     edgeDirection = 135;
255 #else
256                 /*###  GET EDGE DIRECTION (fast way) ### */
257                 int edgeDirection = 0; /*x,y=0*/
258                 if (sumX==0)
259                     {
260                     if (sumY!=0)
261                         edgeDirection = 90;
262                     }
263                 else
264                    {
265                    /*long slope = sumY*1024/sumX;*/
266                    long slope = (sumY << 10)/sumX;
267                    if (slope > 2472 || slope< -2472)  /*tan(67.5)*1024*/
268                        edgeDirection = 90;
269                    else if (slope > 414) /*tan(22.5)*1024*/
270                        edgeDirection = 45;
271                    else if (slope < -414) /*-tan(22.5)*1024*/
272                        edgeDirection = 135;
273                    }
275 #endif
276                 /* printf("%ld %ld %f %d\n", sumX, sumY, orient, edgeDirection); */
278                 /*### Get two adjacent pixels in edge direction ### */
279                 unsigned long leftPixel;
280                 unsigned long rightPixel;
281                 if (edgeDirection == 0)
282                     {
283                     leftPixel  = gm->getPixel(gm, x-1, y);
284                     rightPixel = gm->getPixel(gm, x+1, y);
285                     }
286                 else if (edgeDirection == 45)
287                     {
288                     leftPixel  = gm->getPixel(gm, x-1, y+1);
289                     rightPixel = gm->getPixel(gm, x+1, y-1);
290                     }
291                 else if (edgeDirection == 90)
292                     {
293                     leftPixel  = gm->getPixel(gm, x, y-1);
294                     rightPixel = gm->getPixel(gm, x, y+1);
295                     }
296                 else /*135 */
297                     {
298                     leftPixel  = gm->getPixel(gm, x-1, y-1);
299                     rightPixel = gm->getPixel(gm, x+1, y+1);
300                     }
302                 /*### Compare current value to adjacent pixels ### */
303                 /*### if less that either, suppress it ### */
304                 if (sum < leftPixel || sum < rightPixel)
305                     sum = 0;
306                 else
307                     {
308                     unsigned long highThreshold = 
309                           (unsigned long)(dHighThreshold * 765.0);
310                     unsigned long lowThreshold = 
311                           (unsigned long)(dLowThreshold * 765.0);
312                     if (sum >= highThreshold)
313                         sum = 765; /* EDGE.  3*255 this needs to be settable */
314                     else if (sum < lowThreshold)
315                         sum = 0; /* NONEDGE */
316                     else
317                         {
318                         if ( gm->getPixel(gm, x-1, y-1)> highThreshold ||
319                              gm->getPixel(gm, x  , y-1)> highThreshold ||
320                              gm->getPixel(gm, x+1, y-1)> highThreshold ||
321                              gm->getPixel(gm, x-1, y  )> highThreshold ||
322                              gm->getPixel(gm, x+1, y  )> highThreshold ||
323                              gm->getPixel(gm, x-1, y+1)> highThreshold ||
324                              gm->getPixel(gm, x  , y+1)> highThreshold ||
325                              gm->getPixel(gm, x+1, y+1)> highThreshold)
326                             sum = 765; /* EDGE fix me too */
327                         else
328                             sum = 0; /* NONEDGE */
329                         }
330                     }
333                 }/* else */
334             if (sum==0) /* invert light & dark */
335                 sum = 765;
336             else
337                 sum = 0;
338             newGm->setPixel(newGm, x, y, sum);
339             }/* for (x) */
340         }/* for (y) */
342     return newGm;
349 /**
350  *
351  */
352 GrayMap *
353 grayMapCanny(GrayMap *gm, double lowThreshold, double highThreshold)
355     if (!gm)
356         return NULL;
358     GrayMap *cannyGm = grayMapSobel(gm, lowThreshold, highThreshold);
359     if (!cannyGm)
360         return NULL;
361     /*cannyGm->writePPM(cannyGm, "canny.ppm");*/
363     return cannyGm;
372 /**
373  *
374  */
375 GdkPixbuf *
376 gdkCanny(GdkPixbuf *img, double lowThreshold, double highThreshold)
378     if (!img)
379         return NULL;
382     GrayMap *grayMap = gdkPixbufToGrayMap(img);
383     if (!grayMap)
384         return NULL;
386     /*grayMap->writePPM(grayMap, "gbefore.ppm");*/
388     GrayMap *cannyGm = grayMapCanny(grayMap,lowThreshold, highThreshold);
390     grayMap->destroy(grayMap);
392     if (!cannyGm)
393         return NULL;
395     /*grayMap->writePPM(grayMap, "gafter.ppm");*/
397     GdkPixbuf *newImg = grayMapToGdkPixbuf(cannyGm);
400     return newImg;
403 /*#########################################################################
404 ### Q U A N T I Z A T I O N
405 #########################################################################*/
407 /**
408  *  Experimental.  Work on this later
409  */
410 GrayMap *quantizeBand(RgbMap *rgbMap, int nrColors)
413     RgbMap *gaussMap = rgbMapGaussian(rgbMap);
414     //gaussMap->writePPM(gaussMap, "rgbgauss.ppm");
416     IndexedMap *qMap = rgbMapQuantize(gaussMap, nrColors);
417     //qMap->writePPM(qMap, "rgbquant.ppm");
418     gaussMap->destroy(gaussMap);
420     GrayMap *gm = GrayMapCreate(rgbMap->width, rgbMap->height);
422     // RGB is quantized.  There should now be a small set of (R+G+B)
423     for (int y=0 ; y<qMap->height ; y++)
424         {
425         for (int x=0 ; x<qMap->width ; x++)
426             {
427             RGB rgb = qMap->getPixelValue(qMap, x, y);
428             int sum = rgb.r + rgb.g + rgb.b;
429             if (sum & 1)
430                 sum = 765;
431             else
432                 sum = 0;
433             // printf("%d %d %d : %d\n", rgb.r, rgb.g, rgb.b, index);
434             gm->setPixel(gm, x, y, sum);
435             }
436         }
438     qMap->destroy(qMap);
440     return gm;
444 /*#########################################################################
445 ### E N D    O F    F I L E
446 #########################################################################*/