From befe399a4e7e5b2cc44eacb08dea92a1c3489e9c Mon Sep 17 00:00:00 2001 From: "Mirar (Pontus Hagland)" <pike@sort.mirar.org> Date: Wed, 15 Apr 1998 19:36:19 +0200 Subject: [PATCH] `==, `<, `>, average, min, max, sum, sumf, find_min, find_max added Rev: src/modules/Image/image.c:1.98 Rev: src/modules/Image/image.h:1.20 Rev: src/modules/Image/operator.c:1.14 --- src/modules/Image/image.c | 36 ++- src/modules/Image/image.h | 16 +- src/modules/Image/operator.c | 589 ++++++++++++++++++++++++++++++++++- 3 files changed, 630 insertions(+), 11 deletions(-) diff --git a/src/modules/Image/image.c b/src/modules/Image/image.c index 318884c43b..d90e6cf22a 100644 --- a/src/modules/Image/image.c +++ b/src/modules/Image/image.c @@ -1,9 +1,9 @@ -/* $Id: image.c,v 1.97 1998/04/06 02:36:58 mirar Exp $ */ +/* $Id: image.c,v 1.98 1998/04/15 17:36:15 mirar Exp $ */ /* **! module Image **! note -**! $Id: image.c,v 1.97 1998/04/06 02:36:58 mirar Exp $ +**! $Id: image.c,v 1.98 1998/04/15 17:36:15 mirar Exp $ **! class image **! **! The main object of the <ref>Image</ref> module, this object @@ -82,7 +82,7 @@ #include "stralloc.h" #include "global.h" -RCSID("$Id: image.c,v 1.97 1998/04/06 02:36:58 mirar Exp $"); +RCSID("$Id: image.c,v 1.98 1998/04/15 17:36:15 mirar Exp $"); #include "pike_macros.h" #include "object.h" #include "constants.h" @@ -3417,15 +3417,35 @@ void pike_module_init(void) "function(:object)",0); add_function("`-",image_operator_minus, - "function(object|array(int):object)",0); + "function(object|array(int)|int:object)",0); add_function("`+",image_operator_plus, - "function(object|array(int):object)",0); + "function(object|array(int)|int:object)",0); add_function("`*",image_operator_multiply, - "function(object|array(int):object)",0); + "function(object|array(int)|int:object)",0); add_function("`&",image_operator_minimum, - "function(object|array(int):object)",0); + "function(object|array(int)|int:object)",0); add_function("`|",image_operator_maximum, - "function(object|array(int):object)",0); + "function(object|array(int)|int:object)",0); + + add_function("`==",image_operator_equal, + "function(object|array(int)|int:int)",0); + add_function("`<",image_operator_lesser, + "function(object|array(int)|int:int)",0); + add_function("`>",image_operator_greater, + "function(object|array(int)|int:int)",0); + + add_function("min",image_min,"function(:array(int))",0); + add_function("max",image_max,"function(:array(int))",0); + add_function("sum",image_sum,"function(:array(int))",0); + add_function("sumf",image_sumf,"function(:array(int))",0); + add_function("average",image_average,"function(:array(int))",0); + + add_function("find_min",image_find_min, + "function(:array(int))|" + "function(int,int,int:array(int))",0); + add_function("find_max",image_find_max, + "function(:array(int))|" + "function(int,int,int:array(int))",0); add_function("read_lsb_rgb",image_read_lsb_rgb, "function(:object)",0); diff --git a/src/modules/Image/image.h b/src/modules/Image/image.h index c031c8b0a3..3440386a90 100644 --- a/src/modules/Image/image.h +++ b/src/modules/Image/image.h @@ -1,7 +1,7 @@ /* **! module Image **! note -**! $Id: image.h,v 1.19 1998/03/11 20:44:50 mirar Exp $ +**! $Id: image.h,v 1.20 1998/04/15 17:36:18 mirar Exp $ */ #ifdef PIKE_IMAGE_IMAGE_H @@ -128,8 +128,22 @@ void image_operator_plus(INT32 args); void image_operator_multiply(INT32 args); void image_operator_maximum(INT32 args); void image_operator_minimum(INT32 args); + +void image_operator_equal(INT32 args); +void image_operator_lesser(INT32 args); +void image_operator_greater(INT32 args); + void image_cast(INT32 args); +void image_min(INT32 args); +void image_max(INT32 args); +void image_sum(INT32 args); +void image_sumf(INT32 args); +void image_average(INT32 args); + +void image_find_max(INT32 args); +void image_find_min(INT32 args); + /* x.c */ void image_to8bit_closest(INT32 args); diff --git a/src/modules/Image/operator.c b/src/modules/Image/operator.c index 6b9a2bb365..ad05376e25 100644 --- a/src/modules/Image/operator.c +++ b/src/modules/Image/operator.c @@ -1,9 +1,9 @@ -/* $Id: operator.c,v 1.13 1998/01/25 10:13:49 mirar Exp $ */ +/* $Id: operator.c,v 1.14 1998/04/15 17:36:19 mirar Exp $ */ /* **! module Image **! note -**! $Id: operator.c,v 1.13 1998/01/25 10:13:49 mirar Exp $ +**! $Id: operator.c,v 1.14 1998/04/15 17:36:19 mirar Exp $ **! class image */ @@ -303,3 +303,588 @@ STANDARD_OPERATOR_HEADER("`& 'minimum'") } +/* +**! method int `==(object operand) +**! method int `==(array(int) color) +**! method int `==(int value) +**! method int `<(object operand) +**! method int `<(array(int) color) +**! method int `<(int value) +**! method int `>(object operand) +**! method int `>(array(int) color) +**! method int `>(int value) +**! Compares an image with another image or a color. +**! +**! Comparision is strict and on pixel-by-pixel basis. +**! (Means if not all pixel r,g,b values are +**! correct compared with the corresponding +**! pixel values, 0 is returned.) +**! +**! returns true (1) or false (0). +**! +**! arg object operand +**! the other image to compare with; +**! the images must have the same size. +**! arg array(int) color +**! an array in format ({r,g,b}), this is equal +**! to using an uniform-colored image. +**! arg int value +**! equal to ({value,value,value}). +**! +**! see also: `-, `+, `|, `*, `& +**! +**! note: +**! `< or `> on empty ("no image") image objects or images +**! with different size will result in an error. +**! `== is always true on two empty image objects and +**! always false if one and only one of the image objects +**! is empty or the images differs in size. +**! +**! a>=b and a<=b between objects is equal to !(a<b) and !(a>b), +**! which may not be what you want (since both < and > can return +**! false, comparing the same images). +*/ + +void image_operator_equal(INT32 args) +{ + struct image *oper; + rgb_group *s1,*s2,rgb; + INT32 i; + int res=1; + + if (args && sp[-args].type==T_INT) + { + rgb.r=sp[-args].u.integer; + rgb.g=sp[-args].u.integer; + rgb.b=sp[-args].u.integer; + oper=NULL; + if (!THIS->img) + { + pop_n_elems(args); + push_int(1); /* no image has all colors */ + return; + } + } + else if (args && sp[-args].type==T_ARRAY + && sp[-args].u.array->size>=3 + && sp[-args].u.array->item[0].type==T_INT + && sp[-args].u.array->item[1].type==T_INT + && sp[-args].u.array->item[2].type==T_INT) + { + rgb.r=sp[-args].u.array->item[0].u.integer; + rgb.g=sp[-args].u.array->item[1].u.integer; + rgb.b=sp[-args].u.array->item[2].u.integer; + oper=NULL; + if (!THIS->img) + { + pop_n_elems(args); + push_int(1); /* no image has all colors */ + return; + } + } + else + { + if (args<1 || sp[-args].type!=T_OBJECT + || !sp[-args].u.object + || !(oper=(struct image*)get_storage(sp[-args].u.object,image_program))) + error("`==: illegal argument 2\n"); + + if (!oper->img || !THIS->img) + { + pop_n_elems(args); + push_int(oper->img == THIS->img); /* 1 if NULL == NULL */ + return; + } + if (oper->xsize!=THIS->xsize + || oper->ysize!=THIS->ysize) + { + pop_n_elems(args); + push_int(0); + return; + } + } + + s1=THIS->img; + if (oper) s2=oper->img; else s2=NULL; + + if (s1==s2) + { + pop_n_elems(args); + push_int(1); + return; /* same image is equal */ + } + + i=THIS->xsize*THIS->ysize; + THREADS_ALLOW(); + if (s2) + while (i--) + { + if (s1->r!=s1->r || s1->g!=s1->g || s1->b!=s1->b) { res=0; break; } + s1++; s2++; + } + else + while (i--) + { + if (s1->r!=rgb.r || s1->g!=rgb.g || s1->b!=rgb.b) { res=0; break; } + s1++; + } + THREADS_DISALLOW(); + pop_n_elems(args); + push_int(res); +} + +void image_operator_lesser(INT32 args) +{ + struct image *oper; + rgb_group *s1,*s2,rgb; + INT32 i; + int res=1; + + if (!THIS->img) + error("image->`<: operator 1 has no image\n"); + + if (args && sp[-args].type==T_INT) + { + rgb.r=sp[-args].u.integer; + rgb.g=sp[-args].u.integer; + rgb.b=sp[-args].u.integer; + oper=NULL; + } + else if (args && sp[-args].type==T_ARRAY + && sp[-args].u.array->size>=3 + && sp[-args].u.array->item[0].type==T_INT + && sp[-args].u.array->item[1].type==T_INT + && sp[-args].u.array->item[2].type==T_INT) + { + rgb.r=sp[-args].u.array->item[0].u.integer; + rgb.g=sp[-args].u.array->item[1].u.integer; + rgb.b=sp[-args].u.array->item[2].u.integer; + oper=NULL; + } + else + { + if (args<1 || sp[-args].type!=T_OBJECT + || !sp[-args].u.object + || !(oper=(struct image*)get_storage(sp[-args].u.object,image_program))) + error("`==: illegal argument 2\n"); + + if (!oper->img) + error("image->`<: operator 2 has no image\n"); + if (oper->xsize!=THIS->xsize + || oper->ysize!=THIS->ysize) + error("image->`<: operators differ in size\n"); + } + + s1=THIS->img; + if (oper) s2=oper->img; else s2=NULL; + + if (s1==s2) + { + pop_n_elems(args); + push_int(0); + return; /* same image is not less */ + } + + i=THIS->xsize*THIS->ysize; + THREADS_ALLOW(); + if (s2) + while (i--) + { + if (s1->r>=s1->r || s1->g>=s1->g || s1->b>=s1->b) { res=0; break; } + s1++; s2++; + } + else + while (i--) + { + if (s1->r>=rgb.r || s1->g>=rgb.g || s1->b>=rgb.b) { res=0; break; } + s1++; + } + THREADS_DISALLOW(); + pop_n_elems(args); + push_int(res); +} + + +void image_operator_greater(INT32 args) +{ + struct image *oper; + rgb_group *s1,*s2,rgb; + INT32 i; + int res=1; + + if (!THIS->img) + error("image->`>: operator 1 has no image\n"); + + if (args && sp[-args].type==T_INT) + { + rgb.r=sp[-args].u.integer; + rgb.g=sp[-args].u.integer; + rgb.b=sp[-args].u.integer; + oper=NULL; + } + else if (args && sp[-args].type==T_ARRAY + && sp[-args].u.array->size>=3 + && sp[-args].u.array->item[0].type==T_INT + && sp[-args].u.array->item[1].type==T_INT + && sp[-args].u.array->item[2].type==T_INT) + { + rgb.r=sp[-args].u.array->item[0].u.integer; + rgb.g=sp[-args].u.array->item[1].u.integer; + rgb.b=sp[-args].u.array->item[2].u.integer; + oper=NULL; + } + else + { + if (args<1 || sp[-args].type!=T_OBJECT + || !sp[-args].u.object + || !(oper=(struct image*)get_storage(sp[-args].u.object,image_program))) + error("`==: illegal argument 2\n"); + + if (!oper->img) + error("image->`>: operator 2 has no image\n"); + if (oper->xsize!=THIS->xsize + || oper->ysize!=THIS->ysize) + error("image->`>: operators differ in size\n"); + } + + s1=THIS->img; + if (oper) s2=oper->img; else s2=NULL; + + if (s1==s2) + { + pop_n_elems(args); + push_int(0); + return; /* same image is not less */ + } + + i=THIS->xsize*THIS->ysize; + THREADS_ALLOW(); + if (s2) + while (i--) + { + if (s1->r<=s1->r || s1->g<=s1->g || s1->b<=s1->b) { res=0; break; } + s1++; s2++; + } + else + while (i--) + { + if (s1->r<=rgb.r || s1->g<=rgb.g || s1->b<=rgb.b) { res=0; break; } + s1++; + } + THREADS_DISALLOW(); + pop_n_elems(args); + push_int(res); +} + + +/* +**! method array(float) average() +**! method array(int) min() +**! method array(int) max() +**! method array(int) sum() +**! method array(float) sumf() +**! Gives back the average, minimum, maximum color value, +**! and the sum of all pixel's color value. +**! +**! note: +**! sum() values can wrap! Most systems only have 31 bits +**! available for positive integers. (Meaning, be careful +**! with images that have more than 8425104 pixels.) +**! +**! average() and sumf() may also wrap, but on a line basis. +**! (Meaning, be careful with images that are wider +**! than 8425104 pixels.) These functions may have a precision +**! problem instead, during to limits in the 'double' C type and/or +**! 'float' Pike type. +*/ + +void image_average(INT32 args) +{ + unsigned long x,y,xz; + struct { double r,g,b; } sumy={0.0,0.0,0.0}; + rgb_group *s=THIS->img; + + pop_n_elems(args); + + if (!THIS->img) + error("Image.image->average(): no image\n"); + if (!THIS->xsize || !THIS->ysize) + error("Image.image->average(): no pixels in image (division by zero)\n"); + + y=THIS->ysize; + xz=THIS->xsize; + THREADS_ALLOW(); + while (y--) + { + rgbl_group sumx={0,0,0}; + x=xz; + while (x--) + { + sumx.r+=s->r; + sumx.g+=s->g; + sumx.b+=s->b; + s++; + } + sumy.r+=((float)sumx.r)/(float)xz; + sumy.g+=((float)sumx.g)/(float)xz; + sumy.b+=((float)sumx.b)/(float)xz; + } + THREADS_DISALLOW(); + + push_float(sumy.r/(float)THIS->ysize); + push_float(sumy.g/(float)THIS->ysize); + push_float(sumy.b/(float)THIS->ysize); + + f_aggregate(3); +} + + +void image_sumf(INT32 args) +{ + unsigned long x,y,xz; + struct { double r,g,b; } sumy={0.0,0.0,0.0}; + rgb_group *s=THIS->img; + + pop_n_elems(args); + + if (!THIS->img) + error("Image.image->sumf(): no image\n"); + + y=THIS->ysize; + xz=THIS->xsize; + THREADS_ALLOW(); + while (y--) + { + rgbl_group sumx={0,0,0}; + x=xz; + while (x--) + { + sumx.r+=s->r; + sumx.g+=s->g; + sumx.b+=s->b; + s++; + } + sumy.r+=(float)sumx.r; + sumy.g+=(float)sumx.g; + sumy.b+=(float)sumx.b; + } + THREADS_DISALLOW(); + + push_float(sumy.r); + push_float(sumy.g); + push_float(sumy.b); + + f_aggregate(3); +} + +void image_sum(INT32 args) +{ + unsigned long n; + rgb_group *s=THIS->img; + rgbl_group sum={0,0,0}; + + pop_n_elems(args); + + if (!THIS->img) + error("Image.image->sum(): no image\n"); + + n=THIS->ysize*THIS->xsize; + THREADS_ALLOW(); + while (n--) + { + sum.r+=s->r; + sum.g+=s->g; + sum.b+=s->b; + s++; + } + THREADS_DISALLOW(); + + push_int(sum.r); + push_int(sum.g); + push_int(sum.b); + + f_aggregate(3); +} + +void image_min(INT32 args) +{ + unsigned long n; + rgb_group *s=THIS->img; + rgb_group x={255,255,255}; + + pop_n_elems(args); + + if (!THIS->img) + error("Image.image->min(): no image\n"); + + n=THIS->ysize*THIS->xsize; + THREADS_ALLOW(); + while (n--) + { + if (x.r>s->r) x.r=s->r; + if (x.g>s->g) x.g=s->g; + if (x.b>s->b) x.b=s->b; + s++; + } + THREADS_DISALLOW(); + + push_int(x.r); + push_int(x.g); + push_int(x.b); + + f_aggregate(3); +} + +void image_max(INT32 args) +{ + unsigned long n; + rgb_group *s=THIS->img; + rgb_group x={0,0,0}; + + pop_n_elems(args); + + if (!THIS->img) + error("Image.image->max(): no image\n"); + + n=THIS->ysize*THIS->xsize; + THREADS_ALLOW(); + while (n--) + { + if (x.r<s->r) x.r=s->r; + if (x.g<s->g) x.g=s->g; + if (x.b<s->b) x.b=s->b; + s++; + } + THREADS_DISALLOW(); + + push_int(x.r); + push_int(x.g); + push_int(x.b); + + f_aggregate(3); +} + + +/* +**! method array(int) find_min() +**! method array(int) find_max() +**! method array(int) find_min(int r,int g,int b) +**! method array(int) find_max(int r,int g,int b) +**! Gives back the position of the minimum or maximum +**! pixel value, weighted to grey. +**! +**! arg int r +**! arg int g +**! arg int b +**! weight of color, default is r=87,g=127,b=41, same +**! as the <ref>grey</ref>() method. +*/ + +static INLINE void getrgbl(rgbl_group *rgb,INT32 args_start,INT32 args,char *name) +{ + INT32 i; + if (args-args_start<3) return; + for (i=0; i<3; i++) + if (sp[-args+i+args_start].type!=T_INT) + error("Illegal r,g,b argument to %s\n",name); + rgb->r=sp[-args+args_start].u.integer; + rgb->g=sp[1-args+args_start].u.integer; + rgb->b=sp[2-args+args_start].u.integer; +} + +void image_find_min(INT32 args) +{ + unsigned long x,y,xz,xp=0,yp=0,yz; + rgb_group *s=THIS->img; + rgbl_group rgb; + double div,min; + + if (args<3) + { + rgb.r=87; + rgb.g=127; + rgb.b=41; + } + else + getrgbl(&rgb,0,args,"Image.image->find_min()"); + if (rgb.r||rgb.g||rgb.b) + div=1.0/(rgb.r+rgb.g+rgb.b); + else + div=1.0; + + pop_n_elems(args); + + if (!THIS->img) + error("Image.image->find_min(): no image\n"); + if (!THIS->xsize || !THIS->ysize) + error("Image.image->find_min(): no pixels in image (none to find)\n"); + + yz=THIS->ysize; + xz=THIS->xsize; + min=(rgb.r+rgb.g+rgb.b)*256.0; + THREADS_ALLOW(); + for (y=0; y<yz; y++) + { + for (x=0; x<xz; x++) + { + double val=(s->r*rgb.r+s->g*rgb.g+s->b*rgb.b)*div; + if (val<min) xp=x,yp=y,min=val; + s++; + } + } + THREADS_DISALLOW(); + + push_int(xp); + push_int(yp); + + f_aggregate(2); +} + +void image_find_max(INT32 args) +{ + unsigned long x,y,xz,xp=0,yp=0,yz; + rgb_group *s=THIS->img; + rgbl_group rgb; + double div,max; + + if (args<3) + { + rgb.r=87; + rgb.g=127; + rgb.b=41; + } + else + getrgbl(&rgb,0,args,"Image.image->find_max()"); + if (rgb.r||rgb.g||rgb.b) + div=1.0/(rgb.r+rgb.g+rgb.b); + else + div=1.0; + + pop_n_elems(args); + + if (!THIS->img) + error("Image.image->find_max(): no image\n"); + if (!THIS->xsize || !THIS->ysize) + error("Image.image->find_max(): no pixels in image (none to find)\n"); + + yz=THIS->ysize; + xz=THIS->xsize; + max=0.0; + THREADS_ALLOW(); + for (y=0; y<yz; y++) + { + for (x=0; x<xz; x++) + { + double val=(s->r*rgb.r+s->g*rgb.g+s->b*rgb.b)*div; + if (val>max) xp=x,yp=y,max=val; + s++; + } + } + THREADS_DISALLOW(); + + push_int(xp); + push_int(yp); + + f_aggregate(2); +} + -- GitLab