9 filters.c - implements filters that operate on images
20 filters.c implements basic filters for Imager. These filters
21 should be accessible from the filter interface as defined in
24 =head1 FUNCTION REFERENCE
26 Some of these functions are internal.
40 =item i_contrast(im, intensity)
42 Scales the pixel values by the amount specified.
45 intensity - scalefactor
51 i_contrast(i_img *im, float intensity) {
54 unsigned int new_color;
57 mm_log((1,"i_contrast(im %p, intensity %f)\n", im, intensity));
59 if(intensity < 0) return;
61 for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
62 i_gpix(im, x, y, &rcolor);
64 for(ch = 0; ch < im->channels; ch++) {
65 new_color = (unsigned int) rcolor.channel[ch];
66 new_color *= intensity;
71 rcolor.channel[ch] = (unsigned char) new_color;
73 i_ppix(im, x, y, &rcolor);
79 =item i_hardinvert(im)
81 Inverts the pixel values of the input image.
89 i_hardinvert(i_img *im) {
95 mm_log((1,"i_hardinvert(im %p)\n", im));
97 for(y = 0; y < im->ysize; y++) {
98 for(x = 0; x < im->xsize; x++) {
99 i_gpix(im, x, y, &rcolor);
101 for(ch = 0; ch < im->channels; ch++) {
102 rcolor.channel[ch] = 255 - rcolor.channel[ch];
105 i_ppix(im, x, y, &rcolor);
113 =item i_noise(im, amount, type)
115 Inverts the pixel values by the amount specified.
118 amount - deviation in pixel values
119 type - noise individual for each channel if true
125 /* random() is non-ASCII, even if it is better than rand() */
126 #define random() rand()
130 i_noise(i_img *im, float amount, unsigned char type) {
134 float damount = amount * 2;
138 mm_log((1,"i_noise(im %p, intensity %.2f\n", im, amount));
140 if(amount < 0) return;
142 for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
143 i_gpix(im, x, y, &rcolor);
146 color_inc = (amount - (damount * ((float)random() / RAND_MAX)));
149 for(ch = 0; ch < im->channels; ch++) {
150 new_color = (int) rcolor.channel[ch];
153 new_color += (amount - (damount * ((float)random() / RAND_MAX)));
155 new_color += color_inc;
161 if(new_color > 255) {
165 rcolor.channel[ch] = (unsigned char) new_color;
168 i_ppix(im, x, y, &rcolor);
174 =item i_noise(im, amount, type)
176 Inverts the pixel values by the amount specified.
179 amount - deviation in pixel values
180 type - noise individual for each channel if true
187 =item i_applyimage(im, add_im, mode)
189 Apply's an image to another image
192 add_im - image that is applied to target
193 mode - what method is used in applying:
213 void i_applyimage(i_img *im, i_img *add_im, unsigned char mode) {
217 mm_log((1, "i_applyimage(im %p, add_im %p, mode %d", im, add_im, mode));
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;
222 for(x = 0; x < mx; x++) {
223 for(y = 0; y < my; y++) {
230 =item i_bumpmap(im, bump, channel, light_x, light_y, st)
232 Makes a bumpmap on image im using the bump image as the elevation map.
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
245 i_bumpmap(i_img *im, i_img *bump, int channel, int light_x, int light_y, int st) {
248 i_color x1_color, y1_color, x2_color, y2_color, dst_color;
253 unsigned char px1, px2, py1, py2;
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));
261 if(channel >= bump->channels) {
262 mm_log((1, "i_bumpmap: channel = %d while bump image only has %d channels\n", channel, bump->channels));
266 mx = (bump->xsize <= im->xsize) ? bump->xsize : im->xsize;
267 my = (bump->ysize <= im->ysize) ? bump->ysize : im->ysize;
269 i_img_empty_ch(&new_im, im->xsize, im->ysize, im->channels);
271 aX = (light_x > (mx >> 1)) ? light_x : mx - light_x;
272 aY = (light_y > (my >> 1)) ? light_y : my - light_y;
274 aL = sqrt((aX * aX) + (aY * aY));
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);
283 i_gpix(im, x, y, &dst_color);
285 px1 = x1_color.channel[channel];
286 py1 = y1_color.channel[channel];
287 px2 = x2_color.channel[channel];
288 py2 = y2_color.channel[channel];
296 fZ = (sqrt((nX * nX) + (nY * nY)) / aL);
298 tX = abs(x - light_x) / aL;
299 tY = abs(y - light_y) / aL;
301 tZ = 1 - (sqrt((tX * tX) + (tY * tY)) * fZ);
306 for(ch = 0; ch < im->channels; ch++)
307 dst_color.channel[ch] = (unsigned char) (float)(dst_color.channel[ch] * tZ);
309 i_ppix(&new_im, x, y, &dst_color);
313 i_copyto(im, &new_im, 0, 0, (int)im->xsize, (int)im->ysize, 0, 0);
315 i_img_exorcise(&new_im);
321 =item i_postlevels(im, levels)
323 Quantizes Images to fewer levels.
326 levels - number of levels
332 i_postlevels(i_img *im, int levels) {
340 rv = (int) ((float)(256 / levels));
343 for(y = 0; y < im->ysize; y++) for(x = 0; x < im->xsize; x++) {
344 i_gpix(im, x, y, &rcolor);
346 for(ch = 0; ch < im->channels; ch++) {
347 pv = (((float)rcolor.channel[ch] / 255)) * av;
348 pv = (int) ((int)pv * rv);
351 else if(pv > 255) pv = 255;
353 rcolor.channel[ch] = (unsigned char) pv;
355 i_ppix(im, x, y, &rcolor);
361 =item i_mosaic(im, size)
363 Makes an image looks like a mosaic with tilesize of size
372 i_mosaic(i_img *im, int size) {
380 sqrsize = size * size;
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;
385 for(lx = 0; lx < size; lx++) {
386 for(ly = 0; ly < size; ly++) {
387 i_gpix(im, (x + lx), (y + ly), &rcolor);
389 for(ch = 0; ch < im->channels; ch++) {
390 col[ch] += rcolor.channel[ch];
395 for(ch = 0; ch < im->channels; ch++)
396 rcolor.channel[ch] = (int) ((float)col[ch] / sqrsize);
399 for(lx = 0; lx < size; lx++)
400 for(ly = 0; ly < size; ly++)
401 i_ppix(im, (x + lx), (y + ly), &rcolor);
409 Clamps the input value between 0 and 255. (internal)
419 if (in>255) { return 255; }
420 else if (in>0) return in;
426 =item i_watermark(im, wmark, tx, ty, pixdiff)
428 Applies a watermark to the 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
440 i_watermark(i_img *im, i_img *wmark, int tx, int ty, int pixdiff) {
444 for(vx=0;vx<128;vx++) for(vy=0;vy<110;vy++) {
446 i_gpix(im, tx+vx, ty+vy,&val );
447 i_gpix(wmark, vx, vy, &wval);
449 for(ch=0;ch<im->channels;ch++)
450 val.channel[ch] = saturate( val.channel[ch] + (pixdiff* (wval.channel[0]-128) )/128 );
452 i_ppix(im,tx+vx,ty+vy,&val);
458 =item i_autolevels(im, lsat, usat, skew)
460 Scales and translates each color such that it fills the range completely.
461 Skew is not implemented yet - purpose is to control the color skew that can
462 occur when changing the contrast.
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
473 i_autolevels(i_img *im, float lsat, float usat, float skew) {
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;
481 mm_log((1,"i_autolevels(im %p, lsat %f,usat %f,skew %f)\n", im, lsat,usat,skew));
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]]++;
499 rmin = gmin = bmin = 0;
500 rmax = gmax = bmax = 255;
502 rcu = rcl = gcu = gcl = bcu = bcl = 0;
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;
508 gcl += ghist[i]; if ( (gcl<gsum*lsat) ) gmin=i;
509 gcu += ghist[255-i]; if ( (gcu<gsum*usat) ) gmax=255-i;
511 bcl += bhist[i]; if ( (bcl<bsum*lsat) ) bmin=i;
512 bcu += bhist[255-i]; if ( (bcu<bsum*usat) ) bmax=255-i;
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);
527 Pseudo noise utility function used to generate perlin noise. (internal)
537 Noise(int x, int y) {
540 return ( 1.0 - ( (n * (n * n * 15731 + 789221) + 1376312589) & 0x7fffffff) / 1073741824.0);
544 =item SmoothedNoise1(x,y)
546 Pseudo noise utility function used to generate perlin noise. (internal)
556 SmoothedNoise1(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;
565 =item G_Interpolate(a, b, x)
567 Utility function used to generate perlin noise. (internal)
573 float C_Interpolate(float a, float b, float x) {
574 /* float ft = x * 3.1415927; */
576 float f = (1 - cos(ft)) * .5;
577 return a*(1-f) + b*f;
582 =item InterpolatedNoise(x, y)
584 Utility function used to generate perlin noise. (internal)
591 InterpolatedNoise(float x, float y) {
594 float fractional_X = x - integer_X;
596 float fractional_Y = y - integer_Y;
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);
603 float i1 = C_Interpolate(v1 , v2 , fractional_X);
604 float i2 = C_Interpolate(v3 , v4 , fractional_X);
606 return C_Interpolate(i1 , i2 , fractional_Y);
612 =item PerlinNoise_2D(x, y)
614 Utility function used to generate perlin noise. (internal)
621 PerlinNoise_2D(float x, float y) {
625 int Number_Of_Octaves=6;
626 int n = Number_Of_Octaves - 1;
631 total = total + InterpolatedNoise(x * frequency, y * frequency) * amplitude;
639 =item i_radnoise(im, xo, yo, rscale, ascale)
641 Perlin-like radial noise.
644 xo - x coordinate of center
645 yo - y coordinate of center
646 rscale - radial scale
647 ascale - angular scale
653 i_radnoise(i_img *im, int xo, int yo, float rscale, float ascale) {
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);
674 =item i_turbnoise(im, xo, yo, scale)
676 Perlin-like 2d noise noise.
679 xo - x coordinate translation
680 yo - y coordinate translation
681 scale - scale of noise
687 i_turbnoise(i_img *im, float xo, float yo, float scale) {
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);
703 =item i_gradgen(im, num, xo, yo, ival, dmeasure)
705 Gradient generating function.
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.
714 1 = Euclidean squared
715 2 = Manhattan distance
722 i_gradgen(i_img *im, int num, int *xo, int *yo, i_color *ival, int dmeasure) {
726 int channels = im->channels;
727 int xsize = im->xsize;
728 int ysize = im->ysize;
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));
734 for(p = 0; p<num; p++) {
735 mm_log((1,"i_gradgen: (%d, %d)\n", xo[p], yo[p]));
739 fdist = mymalloc( sizeof(float) * num );
741 for(y = 0; y<ysize; y++) for(x = 0; x<xsize; x++) {
744 for(p = 0; p<num; p++) {
748 case 0: /* euclidean */
749 fdist[p] = sqrt(xd*xd + yd*yd); /* euclidean distance */
751 case 1: /* euclidean squared */
752 fdist[p] = xd*xd + yd*yd; /* euclidean distance */
754 case 2: /* euclidean squared */
755 fdist[p] = max(xd*xd, yd*yd); /* manhattan distance */
758 m_fatal(3,"i_gradgen: Unknown distance measure\n");
763 csd = 1/((num-1)*cs);
765 for(p = 0; p<num; p++) fdist[p] = (cs-fdist[p])*csd;
767 for(ch = 0; ch<channels; ch++) {
769 for(p = 0; p<num; p++) tres += ival[p].channel[ch] * fdist[p];
770 val.channel[ch] = saturate(tres);
772 i_ppix(im, x, y, &val);
793 i_nearest_color_foo(i_img *im, int num, int *xo, int *yo, i_color *ival, int dmeasure) {
796 int xsize = im->xsize;
797 int ysize = im->ysize;
799 mm_log((1,"i_gradgen(im %p, num %d, xo %p, yo %p, ival %p, dmeasure %d)\n", im, num, xo, yo, ival, dmeasure));
801 for(p = 0; p<num; p++) {
802 mm_log((1,"i_gradgen: (%d, %d)\n", xo[p], yo[p]));
806 for(y = 0; y<ysize; y++) for(x = 0; x<xsize; x++) {
815 case 0: /* euclidean */
816 mindist = sqrt(xd*xd + yd*yd); /* euclidean distance */
818 case 1: /* euclidean squared */
819 mindist = xd*xd + yd*yd; /* euclidean distance */
821 case 2: /* euclidean squared */
822 mindist = max(xd*xd, yd*yd); /* manhattan distance */
825 m_fatal(3,"i_nearest_color: Unknown distance measure\n");
828 for(p = 1; p<num; p++) {
832 case 0: /* euclidean */
833 curdist = sqrt(xd*xd + yd*yd); /* euclidean distance */
835 case 1: /* euclidean squared */
836 curdist = xd*xd + yd*yd; /* euclidean distance */
838 case 2: /* euclidean squared */
839 curdist = max(xd*xd, yd*yd); /* manhattan distance */
842 m_fatal(3,"i_nearest_color: Unknown distance measure\n");
844 if (curdist < mindist) {
849 i_ppix(im, x, y, &ival[midx]);
864 i_nearest_color(i_img *im, int num, int *xo, int *yo, i_color *oval, int dmeasure) {
870 int xsize = im->xsize;
871 int ysize = im->ysize;
874 mm_log((1,"i_nearest_color(im %p, num %d, xo %p, yo %p, ival %p, dmeasure %d)\n", im, num, xo, yo, oval, dmeasure));
876 tval = mymalloc( sizeof(float)*num*im->channels );
877 ival = mymalloc( sizeof(i_color)*num );
878 cmatch = mymalloc( sizeof(int)*num );
880 for(p = 0; p<num; p++) {
881 for(ch = 0; ch<im->channels; ch++) tval[ p * im->channels + ch] = 0;
886 for(y = 0; y<ysize; y++) for(x = 0; x<xsize; x++) {
895 case 0: /* euclidean */
896 mindist = sqrt(xd*xd + yd*yd); /* euclidean distance */
898 case 1: /* euclidean squared */
899 mindist = xd*xd + yd*yd; /* euclidean distance */
901 case 2: /* euclidean squared */
902 mindist = max(xd*xd, yd*yd); /* manhattan distance */
905 m_fatal(3,"i_nearest_color: Unknown distance measure\n");
908 for(p = 1; p<num; p++) {
912 case 0: /* euclidean */
913 curdist = sqrt(xd*xd + yd*yd); /* euclidean distance */
915 case 1: /* euclidean squared */
916 curdist = xd*xd + yd*yd; /* euclidean distance */
918 case 2: /* euclidean squared */
919 curdist = max(xd*xd, yd*yd); /* manhattan distance */
922 m_fatal(3,"i_nearest_color: Unknown distance measure\n");
924 if (curdist < mindist) {
931 i_gpix(im, x, y, &val);
932 c2 = 1.0/(float)(cmatch[midx]);
935 // printf("pixel [%d %d %d] c1+c2 = %f\n", val.channel[0], val.channel[1], val.channel[2], c1+c2);
936 // 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] );
938 for(ch = 0; ch<im->channels; ch++)
939 tval[midx*im->channels + ch] = c1*tval[midx*im->channels + ch] + c2 * (float) val.channel[ch];
944 for(p = 0; p<num; p++) for(ch = 0; ch<im->channels; ch++) ival[p].channel[ch] = tval[p*im->channels + ch];
946 i_nearest_color_foo(im, num, xo, yo, ival, dmeasure);