]> git.imager.perl.org - imager.git/blame_incremental - filters.c
Initial revision
[imager.git] / filters.c
... / ...
CommitLineData
1#include "image.h"
2#include <stdlib.h>
3#include <math.h>
4
5
6/*
7=head1 NAME
8
9filters.c - implements filters that operate on images
10
11=head1 SYNOPSIS
12
13
14 i_contrast(im, 0.8);
15 i_hardinvert(im);
16 // and more
17
18=head1 DESCRIPTION
19
20filters.c implements basic filters for Imager. These filters
21should be accessible from the filter interface as defined in
22the pod for Imager.
23
24=head1 FUNCTION REFERENCE
25
26Some of these functions are internal.
27
28=over 4
29
30=cut
31*/
32
33
34
35
36
37
38
39/*
40=item i_contrast(im, intensity)
41
42Scales the pixel values by the amount specified.
43
44 im - image object
45 intensity - scalefactor
46
47=cut
48*/
49
50void
51i_contrast(i_img *im, float intensity) {
52 int x, y;
53 unsigned char ch;
54 unsigned int new_color;
55 i_color rcolor;
56
57 mm_log((1,"i_contrast(im %p, intensity %f)\n", im, intensity));
58
59 if(intensity < 0) return;
60
61 for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
62 i_gpix(im, x, y, &rcolor);
63
64 for(ch = 0; ch < im->channels; ch++) {
65 new_color = (unsigned int) rcolor.channel[ch];
66 new_color *= intensity;
67
68 if(new_color > 255) {
69 new_color = 255;
70 }
71 rcolor.channel[ch] = (unsigned char) new_color;
72 }
73 i_ppix(im, x, y, &rcolor);
74 }
75}
76
77
78/*
79=item i_hardinvert(im)
80
81Inverts the pixel values of the input image.
82
83 im - image object
84
85=cut
86*/
87
88void
89i_hardinvert(i_img *im) {
90 int x, y;
91 unsigned char ch;
92
93 i_color rcolor;
94
95 mm_log((1,"i_hardinvert(im %p)\n", im));
96
97 for(y = 0; y < im->ysize; y++) {
98 for(x = 0; x < im->xsize; x++) {
99 i_gpix(im, x, y, &rcolor);
100
101 for(ch = 0; ch < im->channels; ch++) {
102 rcolor.channel[ch] = 255 - rcolor.channel[ch];
103 }
104
105 i_ppix(im, x, y, &rcolor);
106 }
107 }
108}
109
110
111
112/*
113=item i_noise(im, amount, type)
114
115Inverts the pixel values by the amount specified.
116
117 im - image object
118 amount - deviation in pixel values
119 type - noise individual for each channel if true
120
121=cut
122*/
123
124#ifdef _MSC_VER
125/* random() is non-ASCII, even if it is better than rand() */
126#define random() rand()
127#endif
128
129void
130i_noise(i_img *im, float amount, unsigned char type) {
131 int x, y;
132 unsigned char ch;
133 int new_color;
134 float damount = amount * 2;
135 i_color rcolor;
136 int color_inc = 0;
137
138 mm_log((1,"i_noise(im %p, intensity %.2f\n", im, amount));
139
140 if(amount < 0) return;
141
142 for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
143 i_gpix(im, x, y, &rcolor);
144
145 if(type == 0) {
146 color_inc = (amount - (damount * ((float)random() / RAND_MAX)));
147 }
148
149 for(ch = 0; ch < im->channels; ch++) {
150 new_color = (int) rcolor.channel[ch];
151
152 if(type != 0) {
153 new_color += (amount - (damount * ((float)random() / RAND_MAX)));
154 } else {
155 new_color += color_inc;
156 }
157
158 if(new_color < 0) {
159 new_color = 0;
160 }
161 if(new_color > 255) {
162 new_color = 255;
163 }
164
165 rcolor.channel[ch] = (unsigned char) new_color;
166 }
167
168 i_ppix(im, x, y, &rcolor);
169 }
170}
171
172
173/*
174=item i_noise(im, amount, type)
175
176Inverts the pixel values by the amount specified.
177
178 im - image object
179 amount - deviation in pixel values
180 type - noise individual for each channel if true
181
182=cut
183*/
184
185
186/*
187=item i_applyimage(im, add_im, mode)
188
189Apply's an image to another image
190
191 im - target image
192 add_im - image that is applied to target
193 mode - what method is used in applying:
194
195 0 Normal
196 1 Multiply
197 2 Screen
198 3 Overlay
199 4 Soft Light
200 5 Hard Light
201 6 Color dodge
202 7 Color Burn
203 8 Darker
204 9 Lighter
205 10 Add
206 11 Subtract
207 12 Difference
208 13 Exclusion
209
210=cut
211*/
212
213void i_applyimage(i_img *im, i_img *add_im, unsigned char mode) {
214 int x, y;
215 int mx, my;
216
217 mm_log((1, "i_applyimage(im %p, add_im %p, mode %d", im, add_im, mode));
218
219 mx = (add_im->xsize <= im->xsize) ? add_im->xsize : add_im->xsize;
220 my = (add_im->ysize <= im->ysize) ? add_im->ysize : add_im->ysize;
221
222 for(x = 0; x < mx; x++) {
223 for(y = 0; y < my; y++) {
224 }
225 }
226}
227
228
229/*
230=item i_bumpmap(im, bump, channel, light_x, light_y, st)
231
232Makes a bumpmap on image im using the bump image as the elevation map.
233
234 im - target image
235 bump - image that contains the elevation info
236 channel - to take the elevation information from
237 light_x - x coordinate of light source
238 light_y - y coordinate of light source
239 st - length of shadow
240
241=cut
242*/
243
244void
245i_bumpmap(i_img *im, i_img *bump, int channel, int light_x, int light_y, int st) {
246 int x, y, ch;
247 int mx, my;
248 i_color x1_color, y1_color, x2_color, y2_color, dst_color;
249 double nX, nY;
250 double tX, tY, tZ;
251 double aX, aY, aL;
252 double fZ;
253 unsigned char px1, px2, py1, py2;
254
255 i_img new_im;
256
257 mm_log((1, "i_bumpmap(im %p, add_im %p, channel %d, light_x %d, light_y %d, st %d)\n",
258 im, bump, channel, light_x, light_y, st));
259
260
261 if(channel >= bump->channels) {
262 mm_log((1, "i_bumpmap: channel = %d while bump image only has %d channels\n", channel, bump->channels));
263 return;
264 }
265
266 mx = (bump->xsize <= im->xsize) ? bump->xsize : im->xsize;
267 my = (bump->ysize <= im->ysize) ? bump->ysize : im->ysize;
268
269 i_img_empty_ch(&new_im, im->xsize, im->ysize, im->channels);
270
271 aX = (light_x > (mx >> 1)) ? light_x : mx - light_x;
272 aY = (light_y > (my >> 1)) ? light_y : my - light_y;
273
274 aL = sqrt((aX * aX) + (aY * aY));
275
276 for(y = 1; y < my - 1; y++) {
277 for(x = 1; x < mx - 1; x++) {
278 i_gpix(bump, x + st, y, &x1_color);
279 i_gpix(bump, x, y + st, &y1_color);
280 i_gpix(bump, x - st, y, &x2_color);
281 i_gpix(bump, x, y - st, &y2_color);
282
283 i_gpix(im, x, y, &dst_color);
284
285 px1 = x1_color.channel[channel];
286 py1 = y1_color.channel[channel];
287 px2 = x2_color.channel[channel];
288 py2 = y2_color.channel[channel];
289
290 nX = px1 - px2;
291 nY = py1 - py2;
292
293 nX += 128;
294 nY += 128;
295
296 fZ = (sqrt((nX * nX) + (nY * nY)) / aL);
297
298 tX = abs(x - light_x) / aL;
299 tY = abs(y - light_y) / aL;
300
301 tZ = 1 - (sqrt((tX * tX) + (tY * tY)) * fZ);
302
303 if(tZ < 0) tZ = 0;
304 if(tZ > 2) tZ = 2;
305
306 for(ch = 0; ch < im->channels; ch++)
307 dst_color.channel[ch] = (unsigned char) (float)(dst_color.channel[ch] * tZ);
308
309 i_ppix(&new_im, x, y, &dst_color);
310 }
311 }
312
313 i_copyto(im, &new_im, 0, 0, (int)im->xsize, (int)im->ysize, 0, 0);
314
315 i_img_exorcise(&new_im);
316}
317
318
319
320/*
321=item i_postlevels(im, levels)
322
323Quantizes Images to fewer levels.
324
325 im - target image
326 levels - number of levels
327
328=cut
329*/
330
331void
332i_postlevels(i_img *im, int levels) {
333 int x, y, ch;
334 float pv;
335 int rv;
336 float av;
337
338 i_color rcolor;
339
340 rv = (int) ((float)(256 / levels));
341 av = (float)levels;
342
343 for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
344 i_gpix(im, x, y, &rcolor);
345
346 for(ch = 0; ch < im->channels; ch++) {
347 pv = (((float)rcolor.channel[ch] / 255)) * av;
348 pv = (int) ((int)pv * rv);
349
350 if(pv < 0) pv = 0;
351 else if(pv > 255) pv = 255;
352
353 rcolor.channel[ch] = (unsigned char) pv;
354 }
355 i_ppix(im, x, y, &rcolor);
356 }
357}
358
359
360/*
361=item i_mosaic(im, size)
362
363Makes an image looks like a mosaic with tilesize of size
364
365 im - target image
366 size - size of tiles
367
368=cut
369*/
370
371void
372i_mosaic(i_img *im, int size) {
373 int x, y, ch;
374 int lx, ly, z;
375 long sqrsize;
376
377 i_color rcolor;
378 long col[256];
379
380 sqrsize = size * size;
381
382 for(y = 0; y < im->ysize; y += size) for(x = 0; x < im->xsize; x += size) {
383 for(z = 0; z < 256; z++) col[z] = 0;
384
385 for(lx = 0; lx < size; lx++) {
386 for(ly = 0; ly < size; ly++) {
387 i_gpix(im, (x + lx), (y + ly), &rcolor);
388
389 for(ch = 0; ch < im->channels; ch++) {
390 col[ch] += rcolor.channel[ch];
391 }
392 }
393 }
394
395 for(ch = 0; ch < im->channels; ch++)
396 rcolor.channel[ch] = (int) ((float)col[ch] / sqrsize);
397
398
399 for(lx = 0; lx < size; lx++)
400 for(ly = 0; ly < size; ly++)
401 i_ppix(im, (x + lx), (y + ly), &rcolor);
402
403 }
404}
405
406/*
407=item saturate(in)
408
409Clamps the input value between 0 and 255. (internal)
410
411 in - input integer
412
413=cut
414*/
415
416static
417unsigned char
418saturate(int in) {
419 if (in>255) { return 255; }
420 else if (in>0) return in;
421 return 0;
422}
423
424
425/*
426=item i_watermark(im, wmark, tx, ty, pixdiff)
427
428Applies a watermark to the target image
429
430 im - target image
431 wmark - watermark image
432 tx - x coordinate of where watermark should be applied
433 ty - y coordinate of where watermark should be applied
434 pixdiff - the magnitude of the watermark, controls how visible it is
435
436=cut
437*/
438
439void
440i_watermark(i_img *im, i_img *wmark, int tx, int ty, int pixdiff) {
441 int vx, vy, ch;
442 i_color val, wval;
443
444 for(vx=0;vx<128;vx++) for(vy=0;vy<110;vy++) {
445
446 i_gpix(im, tx+vx, ty+vy,&val );
447 i_gpix(wmark, vx, vy, &wval);
448
449 for(ch=0;ch<im->channels;ch++)
450 val.channel[ch] = saturate( val.channel[ch] + (pixdiff* (wval.channel[0]-128) )/128 );
451
452 i_ppix(im,tx+vx,ty+vy,&val);
453 }
454}
455
456
457/*
458=item i_autolevels(im, lsat, usat, skew)
459
460Scales and translates each color such that it fills the range completely.
461Skew is not implemented yet - purpose is to control the color skew that can
462occur when changing the contrast.
463
464 im - target image
465 lsat - fraction of pixels that will be truncated at the lower end of the spectrum
466 usat - fraction of pixels that will be truncated at the higher end of the spectrum
467 skew - not used yet
468
469=cut
470*/
471
472void
473i_autolevels(i_img *im, float lsat, float usat, float skew) {
474 i_color val;
475 int i, x, y, rhist[256], ghist[256], bhist[256];
476 int rsum, rmin, rmax;
477 int gsum, gmin, gmax;
478 int bsum, bmin, bmax;
479 int rcl, rcu, gcl, gcu, bcl, bcu;
480
481 mm_log((1,"i_autolevels(im %p, lsat %f,usat %f,skew %f)\n", im, lsat,usat,skew));
482
483 rsum=gsum=bsum=0;
484 for(i=0;i<256;i++) rhist[i]=ghist[i]=bhist[i] = 0;
485 /* create histogram for each channel */
486 for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
487 i_gpix(im, x, y, &val);
488 rhist[val.channel[0]]++;
489 ghist[val.channel[1]]++;
490 bhist[val.channel[2]]++;
491 }
492
493 for(i=0;i<256;i++) {
494 rsum+=rhist[i];
495 gsum+=ghist[i];
496 bsum+=bhist[i];
497 }
498
499 rmin = gmin = bmin = 0;
500 rmax = gmax = bmax = 255;
501
502 rcu = rcl = gcu = gcl = bcu = bcl = 0;
503
504 for(i=0; i<256; i++) {
505 rcl += rhist[i]; if ( (rcl<rsum*lsat) ) rmin=i;
506 rcu += rhist[255-i]; if ( (rcu<rsum*usat) ) rmax=255-i;
507
508 gcl += ghist[i]; if ( (gcl<gsum*lsat) ) gmin=i;
509 gcu += ghist[255-i]; if ( (gcu<gsum*usat) ) gmax=255-i;
510
511 bcl += bhist[i]; if ( (bcl<bsum*lsat) ) bmin=i;
512 bcu += bhist[255-i]; if ( (bcu<bsum*usat) ) bmax=255-i;
513 }
514
515 for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
516 i_gpix(im, x, y, &val);
517 val.channel[0]=saturate((val.channel[0]-rmin)*255/(rmax-rmin));
518 val.channel[1]=saturate((val.channel[1]-gmin)*255/(gmax-gmin));
519 val.channel[2]=saturate((val.channel[2]-bmin)*255/(bmax-bmin));
520 i_ppix(im, x, y, &val);
521 }
522}
523
524/*
525=item Noise(x,y)
526
527Pseudo noise utility function used to generate perlin noise. (internal)
528
529 x - x coordinate
530 y - y coordinate
531
532=cut
533*/
534
535static
536float
537Noise(int x, int y) {
538 int n = x + y * 57;
539 n = (n<<13) ^ n;
540 return ( 1.0 - ( (n * (n * n * 15731 + 789221) + 1376312589) & 0x7fffffff) / 1073741824.0);
541}
542
543/*
544=item SmoothedNoise1(x,y)
545
546Pseudo noise utility function used to generate perlin noise. (internal)
547
548 x - x coordinate
549 y - y coordinate
550
551=cut
552*/
553
554static
555float
556SmoothedNoise1(float x, float y) {
557 float corners = ( Noise(x-1, y-1)+Noise(x+1, y-1)+Noise(x-1, y+1)+Noise(x+1, y+1) ) / 16;
558 float sides = ( Noise(x-1, y) +Noise(x+1, y) +Noise(x, y-1) +Noise(x, y+1) ) / 8;
559 float center = Noise(x, y) / 4;
560 return corners + sides + center;
561}
562
563
564/*
565=item G_Interpolate(a, b, x)
566
567Utility function used to generate perlin noise. (internal)
568
569=cut
570*/
571
572static
573float C_Interpolate(float a, float b, float x) {
574 /* float ft = x * 3.1415927; */
575 float ft = x * PI;
576 float f = (1 - cos(ft)) * .5;
577 return a*(1-f) + b*f;
578}
579
580
581/*
582=item InterpolatedNoise(x, y)
583
584Utility function used to generate perlin noise. (internal)
585
586=cut
587*/
588
589static
590float
591InterpolatedNoise(float x, float y) {
592
593 int integer_X = x;
594 float fractional_X = x - integer_X;
595 int integer_Y = y;
596 float fractional_Y = y - integer_Y;
597
598 float v1 = SmoothedNoise1(integer_X, integer_Y);
599 float v2 = SmoothedNoise1(integer_X + 1, integer_Y);
600 float v3 = SmoothedNoise1(integer_X, integer_Y + 1);
601 float v4 = SmoothedNoise1(integer_X + 1, integer_Y + 1);
602
603 float i1 = C_Interpolate(v1 , v2 , fractional_X);
604 float i2 = C_Interpolate(v3 , v4 , fractional_X);
605
606 return C_Interpolate(i1 , i2 , fractional_Y);
607}
608
609
610
611/*
612=item PerlinNoise_2D(x, y)
613
614Utility function used to generate perlin noise. (internal)
615
616=cut
617*/
618
619static
620float
621PerlinNoise_2D(float x, float y) {
622 int i,frequency;
623 float amplitude;
624 float total = 0;
625 int Number_Of_Octaves=6;
626 int n = Number_Of_Octaves - 1;
627
628 for(i=0;i<n;i++) {
629 frequency = 2*i;
630 amplitude = PI;
631 total = total + InterpolatedNoise(x * frequency, y * frequency) * amplitude;
632 }
633
634 return total;
635}
636
637
638/*
639=item i_radnoise(im, xo, yo, rscale, ascale)
640
641Perlin-like radial noise.
642
643 im - target image
644 xo - x coordinate of center
645 yo - y coordinate of center
646 rscale - radial scale
647 ascale - angular scale
648
649=cut
650*/
651
652void
653i_radnoise(i_img *im, int xo, int yo, float rscale, float ascale) {
654 int x, y, ch;
655 i_color val;
656 unsigned char v;
657 float xc, yc, r;
658 double a;
659
660 for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
661 xc = (float)x-xo+0.5;
662 yc = (float)y-yo+0.5;
663 r = rscale*sqrt(xc*xc+yc*yc)+1.2;
664 a = (PI+atan2(yc,xc))*ascale;
665 v = saturate(128+100*(PerlinNoise_2D(a,r)));
666 /* v=saturate(120+12*PerlinNoise_2D(xo+(float)x/scale,yo+(float)y/scale)); Good soft marble */
667 for(ch=0; ch<im->channels; ch++) val.channel[ch]=v;
668 i_ppix(im, x, y, &val);
669 }
670}
671
672
673/*
674=item i_turbnoise(im, xo, yo, scale)
675
676Perlin-like 2d noise noise.
677
678 im - target image
679 xo - x coordinate translation
680 yo - y coordinate translation
681 scale - scale of noise
682
683=cut
684*/
685
686void
687i_turbnoise(i_img *im, float xo, float yo, float scale) {
688 int x,y,ch;
689 unsigned char v;
690 i_color val;
691
692 for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
693 /* v=saturate(125*(1.0+PerlinNoise_2D(xo+(float)x/scale,yo+(float)y/scale))); */
694 v = saturate(120*(1.0+sin(xo+(float)x/scale+PerlinNoise_2D(xo+(float)x/scale,yo+(float)y/scale))));
695 for(ch=0; ch<im->channels; ch++) val.channel[ch] = v;
696 i_ppix(im, x, y, &val);
697 }
698}
699
700
701
702/*
703=item i_gradgen(im, num, xo, yo, ival, dmeasure)
704
705Gradient generating function.
706
707 im - target image
708 num - number of points given
709 xo - array of x coordinates
710 yo - array of y coordinates
711 ival - array of i_color objects
712 dmeasure - distance measure to be used.
713 0 = Euclidean
714 1 = Euclidean squared
715 2 = Manhattan distance
716
717=cut
718*/
719
720
721void
722i_gradgen(i_img *im, int num, int *xo, int *yo, i_color *ival, int dmeasure) {
723
724 i_color val;
725 int p, x, y, ch;
726 int channels = im->channels;
727 int xsize = im->xsize;
728 int ysize = im->ysize;
729
730 float *fdist;
731
732 mm_log((1,"i_gradgen(im %p, num %d, xo %p, yo %p, ival %p, dmeasure %d)\n", im, num, xo, yo, ival, dmeasure));
733
734 for(p = 0; p<num; p++) {
735 mm_log((1,"i_gradgen: (%d, %d)\n", xo[p], yo[p]));
736 ICL_info(&ival[p]);
737 }
738
739 fdist = mymalloc( sizeof(float) * num );
740
741 for(y = 0; y<ysize; y++) for(x = 0; x<xsize; x++) {
742 float cs = 0;
743 float csd = 0;
744 for(p = 0; p<num; p++) {
745 int xd = x-xo[p];
746 int yd = y-yo[p];
747 switch (dmeasure) {
748 case 0: /* euclidean */
749 fdist[p] = sqrt(xd*xd + yd*yd); /* euclidean distance */
750 break;
751 case 1: /* euclidean squared */
752 fdist[p] = xd*xd + yd*yd; /* euclidean distance */
753 break;
754 case 2: /* euclidean squared */
755 fdist[p] = max(xd*xd, yd*yd); /* manhattan distance */
756 break;
757 default:
758 m_fatal(3,"i_gradgen: Unknown distance measure\n");
759 }
760 cs += fdist[p];
761 }
762
763 csd = 1/((num-1)*cs);
764
765 for(p = 0; p<num; p++) fdist[p] = (cs-fdist[p])*csd;
766
767 for(ch = 0; ch<channels; ch++) {
768 int tres = 0;
769 for(p = 0; p<num; p++) tres += ival[p].channel[ch] * fdist[p];
770 val.channel[ch] = saturate(tres);
771 }
772 i_ppix(im, x, y, &val);
773 }
774
775}
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792void
793i_nearest_color_foo(i_img *im, int num, int *xo, int *yo, i_color *ival, int dmeasure) {
794
795 i_color val;
796 int p, x, y, ch;
797 int channels = im->channels;
798 int xsize = im->xsize;
799 int ysize = im->ysize;
800
801 mm_log((1,"i_gradgen(im %p, num %d, xo %p, yo %p, ival %p, dmeasure %d)\n", im, num, xo, yo, ival, dmeasure));
802
803 for(p = 0; p<num; p++) {
804 mm_log((1,"i_gradgen: (%d, %d)\n", xo[p], yo[p]));
805 ICL_info(&ival[p]);
806 }
807
808 for(y = 0; y<ysize; y++) for(x = 0; x<xsize; x++) {
809 int midx = 0;
810 float mindist = 0;
811 float curdist = 0;
812
813 int xd = x-xo[0];
814 int yd = y-yo[0];
815
816 switch (dmeasure) {
817 case 0: /* euclidean */
818 mindist = sqrt(xd*xd + yd*yd); /* euclidean distance */
819 break;
820 case 1: /* euclidean squared */
821 mindist = xd*xd + yd*yd; /* euclidean distance */
822 break;
823 case 2: /* euclidean squared */
824 mindist = max(xd*xd, yd*yd); /* manhattan distance */
825 break;
826 default:
827 m_fatal(3,"i_nearest_color: Unknown distance measure\n");
828 }
829
830 for(p = 1; p<num; p++) {
831 xd = x-xo[p];
832 yd = y-yo[p];
833 switch (dmeasure) {
834 case 0: /* euclidean */
835 curdist = sqrt(xd*xd + yd*yd); /* euclidean distance */
836 break;
837 case 1: /* euclidean squared */
838 curdist = xd*xd + yd*yd; /* euclidean distance */
839 break;
840 case 2: /* euclidean squared */
841 curdist = max(xd*xd, yd*yd); /* manhattan distance */
842 break;
843 default:
844 m_fatal(3,"i_nearest_color: Unknown distance measure\n");
845 }
846 if (curdist < mindist) {
847 mindist = curdist;
848 midx = p;
849 }
850 }
851 i_ppix(im, x, y, &ival[midx]);
852 }
853}
854
855
856
857
858
859
860
861
862
863
864
865void
866i_nearest_color(i_img *im, int num, int *xo, int *yo, i_color *oval, int dmeasure) {
867 i_color *ival;
868 float *tval;
869 float c1, c2;
870 i_color val;
871 int p, x, y, ch;
872 int channels = im->channels;
873 int xsize = im->xsize;
874 int ysize = im->ysize;
875 int *cmatch;
876
877 mm_log((1,"i_nearest_color(im %p, num %d, xo %p, yo %p, ival %p, dmeasure %d)\n", im, num, xo, yo, ival, dmeasure));
878
879
880 tval = mymalloc( sizeof(float)*num*im->channels );
881 ival = mymalloc( sizeof(i_color)*num );
882 cmatch = mymalloc( sizeof(int)*num );
883
884 for(p = 0; p<num; p++) {
885 for(ch = 0; ch<im->channels; ch++) tval[ p * im->channels + ch] = 0;
886 cmatch[p] = 0;
887 }
888
889
890 for(y = 0; y<ysize; y++) for(x = 0; x<xsize; x++) {
891 int midx = 0;
892 float mindist = 0;
893 float curdist = 0;
894
895 int xd = x-xo[0];
896 int yd = y-yo[0];
897
898 switch (dmeasure) {
899 case 0: /* euclidean */
900 mindist = sqrt(xd*xd + yd*yd); /* euclidean distance */
901 break;
902 case 1: /* euclidean squared */
903 mindist = xd*xd + yd*yd; /* euclidean distance */
904 break;
905 case 2: /* euclidean squared */
906 mindist = max(xd*xd, yd*yd); /* manhattan distance */
907 break;
908 default:
909 m_fatal(3,"i_nearest_color: Unknown distance measure\n");
910 }
911
912 for(p = 1; p<num; p++) {
913 xd = x-xo[p];
914 yd = y-yo[p];
915 switch (dmeasure) {
916 case 0: /* euclidean */
917 curdist = sqrt(xd*xd + yd*yd); /* euclidean distance */
918 break;
919 case 1: /* euclidean squared */
920 curdist = xd*xd + yd*yd; /* euclidean distance */
921 break;
922 case 2: /* euclidean squared */
923 curdist = max(xd*xd, yd*yd); /* manhattan distance */
924 break;
925 default:
926 m_fatal(3,"i_nearest_color: Unknown distance measure\n");
927 }
928 if (curdist < mindist) {
929 mindist = curdist;
930 midx = p;
931 }
932 }
933
934 cmatch[midx]++;
935 i_gpix(im, x, y, &val);
936 c2 = 1.0/(float)(cmatch[midx]);
937 c1 = 1.0-c2;
938
939 // printf("pixel [%d %d %d] c1+c2 = %f\n", val.channel[0], val.channel[1], val.channel[2], c1+c2);
940 // printf("cmatch = %d, c1 = %f, c2 = %f tval=[%f %f %f]\n", cmatch[midx], c1, c2, tval[midx*im->channels], tval[midx*im->channels+1], tval[midx*im->channels+2] );
941
942 for(ch = 0; ch<im->channels; ch++)
943 tval[midx*im->channels + ch] = c1*tval[midx*im->channels + ch] + c2 * (float) val.channel[ch];
944
945
946 }
947
948 for(p = 0; p<num; p++) for(ch = 0; ch<im->channels; ch++) ival[p].channel[ch] = tval[p*im->channels + ch];
949
950 i_nearest_color_foo(im, num, xo, yo, ival, dmeasure);
951}