#undef DBL_LOOP /* def for for(x..., for(y... loops */ #undef INL_SORT /* def to inline piksrt() in median() */ /* * process.c - all the image processing functions. */ static char *sccsid = "@(#) process.c 1.3 91/6/9 rosenkra\0\0 "; #include #include "mgif.h" /* * local functions */ int larger (); /* frame processes... */ int zoom (); int smaller (); int cut (); int rotate (); int mirror (); int convolve (); /* area processes... */ int blur (); int median (); int piksrt (); int logscale (); /* point processes... */ int Log2x10 (); int contrast (); int brighten (); int invert (); int threshold (); int histeq (); int redistribute (); int copyrast (); /* others... */ /* * external functions */ extern int do_hist (); extern int copyrast (); /*------------------------------*/ /* larger */ /*------------------------------*/ #define L_BOTH 0 #define L_HOR 1 #define L_VERT 2 int larger (pras, w, h, opt, ptrans) uchar_t *pras; int w; int h; int opt; /* checked by caller! */ uchar_t *ptrans; { /* * enlarge an image (so far 320x200 -> 640x400). return 1 if * successful, else 0. */ register uchar_t *pr; register uchar_t *pt; register long x; register long y; long x2; long y2; register long wold; long hold; register long w2; long h2; /* * fail if enlarged image will be too big for buffer */ #if 0 if ((w > 320) || (h > 200)) return (0); #endif switch (opt) { case L_BOTH: if (4L * (long) w * (long) h > MAXIMG) return (0); break; case L_HOR: if (2L * (long) w * (long) h > MAXIMG) return (0); break; case L_VERT: if (2L * (long) w * (long) h > MAXIMG) return (0); break; } /* * here we always do the transform in situ (in ptrans)... */ if (pras == ptrans) { /* * do in place... */ pr = pras; pt = pras; } else { /* * copy to new image */ pr = pras; pt = ptrans; /* * first copy orig image to transform image */ copyrast (pr, w, h, pt); pr = ptrans; } wold = w; hold = h; switch (opt) { case L_BOTH: /* * set new sizes */ w2 = wold*2L; h2 = hold*2L; /* * shift existing data: * * 0123456789 * 0|**********| *=existing pixels * 1|**********| +=new pixels * . * . * | * v * 1111111111 * 01234567890123456789 * 0| | * 1| + + + + + + + + + +| * 2| | * 3| + + + + + + + + + +| * . * . */ for (y = hold-1; y >= 0; y--) { for (x = wold-1; x >= 0; x--) { x2 = (2*x)+1; y2 = (2*y)+1; pt[y2*w2 + x2] = pt[y*wold + x]; } } /* * now make intermediate points within row (average): * * 1111111111 * 01234567890123456789 * 0| | *=existing pixels * 1|+*+*+*+*+*+*+*+*+*+*| +=new pixels * 2| | * 3|+*+*+*+*+*+*+*+*+*+*| * . * . */ for (y = 1; y < h2; y += 2) { /* first point is duplicate of second */ pt[y*w2 + 0] = pt[y*w2 + 1]; /* others are average */ for (x = 2; x < w2; x += 2) { pt[y*w2 + x] = (uchar_t) ( ((uint_t) pt[y*w2 + (x-1)] + (uint_t) pt[y*w2 + (x+1)]) / 2); } } /* * first row is duplicate of second row: * * 1111111111 * 01234567890123456789 * 0|++++++++++++++++++++|<--- * 1|********************| *=existing pixels * 2| | +=new pixels * 3|********************| * . * . */ for (x = 0; x < w2; x++) { pt[x] = pt[w2 + x]; } /* * finally, make new rows (average): * * 1111111111 * 01234567890123456789 * 0|********************| *=existing pixels * 1|********************| +=new pixels * 2|++++++++++++++++++++|<--- * 3|********************| * . * . */ for (y = 2; y < h2; y += 2) { for (x = 0; x < w2; x++) { pt[y*w2 + x] = (uchar_t) ( ((uint_t) pt[(y-1)*w2 + x] + (uint_t) pt[(y+1)*w2 + x]) / 2); } } break; case L_HOR: /* * set new sizes */ w2 = wold*2L; h2 = hold; /* * shift existing data: * * 0123456789 * 0|**********| *=existing pixels * 1|**********| +=new pixels * . * . * | * v * 1111111111 * 01234567890123456789 * 0| + + + + + + + + + +| * 1| + + + + + + + + + +| * . * . */ for (y = hold-1; y >= 0; y--) { for (x = wold-1; x >= 0; x--) { x2 = (2*x)+1; pt[y*w2 + x2] = pt[y*wold + x]; } } /* * now make intermediate points within row (average): * * 1111111111 * 01234567890123456789 * 0|+*+*+*+*+*+*+*+*+*+*| *=existing pixels * 1|+*+*+*+*+*+*+*+*+*+*| +=new pixels * . * . */ for (y = 0; y < hold; y++) { /* first point is duplicate of second */ pt[y*w2 + 0] = pt[y*w2 + 1]; /* others are average */ for (x = 2; x < w2; x += 2) { pt[y*w2 + x] = (uchar_t) ( ((uint_t) pt[y*w2 + (x-1)] + (uint_t) pt[y*w2 + (x+1)]) / 2); } } break; case L_VERT: /* * set new sizes */ w2 = wold; h2 = hold*2L; /* * shift existing data: * * 0123456789 * 0|**********| *=existing pixels * 1|**********| +=new pixels * . * . * | * v * 0123456789 * 0| | * 1|++++++++++| * 2| | * 3|++++++++++| * . * . */ for (y = hold-1; y >= 0; y--) { for (x = wold-1; x >= 0; x--) { y2 = (2*y)+1; pt[y2*wold + x] = pt[y*wold + x]; } } /* * first row is duplicate of second row: * * 0123456789 * 0|++++++++++|<--- * 1|**********| *=existing pixels * 2| | +=new pixels * 3|**********| * . * . */ for (x = 0; x < wold; x++) { pt[x] = pt[wold + x]; } /* * finally, make new rows (average): * * 0123456789 * 0|**********| *=existing pixels * 1|**********| +=new pixels * 2|++++++++++|<--- * 3|**********| * . * . */ for (y = 2; y < h2; y += 2) { for (x = 0; x < wold; x++) { pt[y*wold + x] = (uchar_t) ( ((uint_t) pt[(y-1)*wold + x] + (uint_t) pt[(y+1)*wold + x]) / 2); } } break; } return (1); } /*------------------------------*/ /* zoom */ /*------------------------------*/ int zoom (pras, w, h, xstart, ystart, ptrans) uchar_t *pras; int w; int h; int xstart; int ystart; uchar_t *ptrans; { /* * zoom in and enlarge an image (so far 2x) starting at xstart,ystart. * return 1 if successful, else 0. */ register uchar_t *pr; register uchar_t *pt; register long x; register long y; long x2; long y2; register long wold; long hold; register long w2; long h2; /* * enlarged image should ALWAYS fit in buffer! * * here we always do the transform in situ (in ptrans)... */ if (pras == ptrans) { /* * do in place. pr points to "cut" area, pt to start */ pr = &pras[xstart + (ystart-1)*w]; pt = pras; /* * shift smaller image to ul corner of pt */ if ((xstart != 0) && (ystart != 0)) { for (y = 0L; y < h/2; y++) { for (x = 0L; x < w/2; x++) { pt[x + w*(y-1)/2] = pr[x + w*(y-1)]; } } } } else { /* * copy to new image */ pr = &pras[xstart + (ystart-1)*w]; pt = ptrans; /* * first copy orig image to transform image */ for (y = 0L; y < h/2; y++) { for (x = 0L; x < w/2; x++) { pt[x + w*(y-1)/2] = pr[x + w*(y-1)]; } } } /* * set new sizes */ wold = w/2L; hold = h/2L; w2 = wold*2L; h2 = hold*2L; /* * shift existing data: * * 0123456789 * 0|**********| *=existing pixels * 1|**********| +=new pixels * . * . * | * v * 1111111111 * 01234567890123456789 * 0| | * 1| + + + + + + + + + +| * 2| | * 3| + + + + + + + + + +| * . * . */ for (y = hold-1; y >= 0; y--) { for (x = wold-1; x >= 0; x--) { x2 = (2*x)+1; y2 = (2*y)+1; pt[y2*w2 + x2] = pt[y*wold + x]; } } /* * now make intermediate points within row (average): * * 1111111111 * 01234567890123456789 * 0| | *=existing pixels * 1|+*+*+*+*+*+*+*+*+*+*| +=new pixels * 2| | * 3|+*+*+*+*+*+*+*+*+*+*| * . * . */ for (y = 1; y < h2; y += 2) { /* first point is duplicate of second */ pt[y*w2 + 0] = pt[y*w2 + 1]; /* others are average */ for (x = 2; x < w2; x += 2) { pt[y*w2 + x] = (uchar_t) ( ((uint_t) pt[y*w2 + (x-1)] + (uint_t) pt[y*w2 + (x+1)]) / 2); } } /* * first row is duplicate of second row: * * 1111111111 * 01234567890123456789 * 0|++++++++++++++++++++|<--- * 1|********************| *=existing pixels * 2| | +=new pixels * 3|********************| * . * . */ for (x = 0; x < w2; x++) { pt[x] = pt[w2 + x]; } /* * finally, make new rows (average): * * 1111111111 * 01234567890123456789 * 0|********************| *=existing pixels * 1|********************| +=new pixels * 2|++++++++++++++++++++|<--- * 3|********************| * . * . */ for (y = 2; y < h2; y += 2) { for (x = 0; x < w2; x++) { pt[y*w2 + x] = (uchar_t) ( ((uint_t) pt[(y-1)*w2 + x] + (uint_t) pt[(y+1)*w2 + x]) / 2); } } return (1); } /*------------------------------*/ /* smaller */ /*------------------------------*/ #define S_BOTH 0 #define S_HOR 1 #define S_VERT 2 int smaller (pras, w, h, opt, ptrans) uchar_t *pras; int w; int h; int opt; /* checked by caller! */ uchar_t *ptrans; { /* * reduce an image by half. return 1 if successful, else 0. */ register uchar_t *pr; register uchar_t *pt; register long x; register long y; register long wold; register long w2; long hold; long h2; /* * there is a limit to what is practical... */ if ((w < 10) || (h < 10)) return (0); if (pras == ptrans) { /* * do in place... */ pr = pras; pt = pras; } else { /* * copy to new image */ pr = pras; pt = ptrans; } /* * do it. skip odd lines and pixels */ wold = w; hold = h; switch (opt) { case S_BOTH: /* * set new sizes */ w2 = wold/2L; h2 = hold/2L; for (y = 0; y < h2; y++) { for (x = 0; x < w2; x++) { pt[y*w2 + x] = pr[2*y*wold + x*2]; } } break; case S_HOR: /* * set new sizes */ w2 = wold/2L; h2 = hold; for (y = 0; y < h2; y++) { for (x = 0; x < w2; x++) { pt[y*w2 + x] = pr[y*wold + x*2]; } } break; case S_VERT: /* * set new sizes */ w2 = wold; h2 = hold/2L; for (y = 0; y < h2; y++) { for (x = 0; x < w2; x++) { pt[y*w2 + x] = pr[2*y*wold + x]; } } break; } return (1); } /*------------------------------*/ /* cut */ /*------------------------------*/ int cut (pras, w, h, x1, y1, x2, y2, ptrans) uchar_t *pras; int w; int h; int x1, y1; int x2, y2; uchar_t *ptrans; { /* * cut out a section of the image from pras to ptrans */ register uchar_t *pr; register uchar_t *pt; register long x; register long y; register long wold; register long w2; register long h2; /* * check for bad coords... */ if ((x1 >= x2) || (y1 >= y2)) return (0); if ((x1 < 0) || (x2 < 0) || (y1 < 0) || (y2 < 0)) return (0); if ((x2 >= w) || (y2 >= h)) return (0); #if 0 if ((x2 > 639) || (y2 > 399)) return (0); if ((x2 - x1) > w) /* don't fail just limit the cut */ x2 = x1 + w; if ((y2 - y1) > h) y2 = y1 + h; #endif /* * set up pointers... */ if (pras == ptrans) { /* * do in place... */ pr = pras; pt = pras; } else { /* * copy to new image */ pr = pras; pt = ptrans; } /* * do it... */ wold = w; w2 = x2 - x1 + 1; h2 = y2 - y1 + 1; for (y = 0; y < h2; y++) { for (x = 0; x < w2; x++) { pt[y*w2 + x] = pr[(y + y1)*wold + (x + x1)]; } } return (1); } /*------------------------------*/ /* rotate */ /*------------------------------*/ int rotate (pras, w, h, angle, ptrans) uchar_t *pras; int w; int h; int angle; /* +90, -90, -180 or +180 */ uchar_t *ptrans; { /* * rotate an image +/-90 or +/-180. does NOT work in place (yet) * * based on (rotating about center): * * xnew = (x * cos(angle)) + (y * sin(angle)) * ynew = (y * cos(angle)) - (x * sin(angle)) * * note: 45's should be relatively simple: * * +45: xnew = (.707 * x) + (.707 * y) * ynew = (.707 * y) - (.707 * x) * * -45: xnew = (.707 * x) - (.707 * y) * ynew = (.707 * y) + (.707 * x) */ register uchar_t *pr; register uchar_t *pt; register long xnew; register long ynew; register long wold; register long hold; /* * set up pointers... */ if (pras == ptrans) { /* * can't do in place (yet)... */ return (0); } /* * copy to new image */ pr = pras; pt = ptrans; /* * do it... */ wold = (long) w; hold = (long) h; switch (angle) { case 90: /* * counter clockwise: * * xnew = y -> y = xnew * ynew = wold - x - 1 x = wold - ynew - 1 * wnew = hold * hnew = wold */ for (ynew = 0L; ynew < wold; ynew++) { for (xnew = 0L; xnew < hold; xnew++) { pt[ynew*hold + xnew] = pr[xnew*wold + (wold-ynew-1)]; } } break; case -90: /* * clockwise... * * xnew = hold - y - 1 -> y = hold - xnew - 1 * ynew = x x = ynew * wnew = hold * hnew = wold */ for (ynew = 0L; ynew < wold; ynew++) { for (xnew = 0L; xnew < hold; xnew++) { pt[ynew*hold + xnew] = pr[(hold-xnew-1)*wold + ynew]; } } break; case 180: case -180: /* * clockwise or counter clockwise... * * xnew = wold - x - 1 -> x = wold - xnew - 1 * ynew = hold - y - 1 y = hold - ynew - 1 * wnew = wold * hnew = hold */ for (ynew = 0L; ynew < hold; ynew++) { for (xnew = 0L; xnew < wold; xnew++) { pt[ynew*wold + xnew] = pr[(hold-ynew-1)*wold + (wold-xnew-1)]; } } break; default: /* * undefined angle, fail... */ return (0); } return (1); } /*------------------------------*/ /* mirror */ /*------------------------------*/ int mirror (pras, w, h, opt, ptrans) uchar_t *pras; int w; int h; int opt; /* 0=vert mirror, 1=horiz mirror */ uchar_t *ptrans; { /* * mirror image. * * vert mirror is: * * _______|_______ * | | | * | | | * | | | * |_______|_______| * | * * horiz mirror is: * * _______________ * | | * __|_______________|__ * | | * |_______________| */ register uchar_t *pr; register uchar_t *pt; register long x; register long y; register uchar_t ctemp; /* * set up pointers... */ if (pras == ptrans) { /* * do in place... */ pr = pras; pt = pras; if (opt) { /* * horizontal mirror */ for (y = 0L; y < h/2; y++) { for (x = 0L; x < w; x++) { ctemp = pt[y*w + x]; pt[y*w + x] = pt[(h-y)*w + x]; pt[(h-y)*w + x] = ctemp; } } } else { /* * vertical mirror */ for (y = 0L; y < h; y++) { for (x = 0L; x < w/2; x++) { ctemp = pt[y*w + x]; pt[y*w + x] = pt[y*w + (w-x)]; pt[y*w + (w-x)] = ctemp; } } } } else { /* * copy to new image */ pr = pras; pt = ptrans; if (opt) { /* * horizontal mirror */ for (y = 0L; y < h; y++) { for (x = 0L; x < w; x++) { pt[y*w + x] = pr[(h-y-1)*w + x]; } } } else { /* * vertical mirror */ for (y = 0L; y < h; y++) { for (x = 0L; x < w; x++) { pt[y*w + x] = pr[y*w + (w-x-1)]; } } } } return (1); } /*------------------------------*/ /* convolve */ /*------------------------------*/ /* * built-in convolution kernels * * k[0..8] is kernel (always 3x3) * k[9] is scaling flag: -1=divide, 1=multiply, 0=no scaling * k[10] is scale * * example: * for lp1 with flag -1 (divide) and scale 9, use * * p = ((p0 * k0) +...+ (p8 * k8)) / 9 * * for hp2 with flag 0 (no scaling), use * * p = (p0 * k0) +...+ (p8 * k8) */ int lp1[11] = { 1, 1, 1, /* low pass */ 1, 1, 1, 1, 1, 1, -1, 9}; int lp2[11] = { 1, 1, 1, 1, 2, 1, 1, 1, 1, -1, 10}; int lp3[11] = { 1, 2, 1, 2, 4, 2, 1, 2, 1, -1, 16}; int hp1[11] = {-1,-1,-1, /* hi pass */ -1, 9,-1, -1,-1,-1, 0, 1}; int hp2[11] = { 0,-1, 0, -1, 5,-1, 0,-1, 0, 0, 1}; int hp3[11] = { 1,-2, 1, -2, 5,-2, 1,-2, 1, 0, 1}; /* shift edge */ int se1[11] = { 0, 0, 0, /* vertical */ -1, 1, 0, 0, 0, 0, 0, 1}; int se2[11] = { 0,-1, 0, /* horizontal */ 0, 1, 0, 0, 0, 0, 0, 1}; int se3[11] = {-1, 0, 0, /* hor and vert */ 0, 1, 0, 0, 0, 0, 0, 1}; /* gradient edge */ int ge1[11] = { 1, 1, 1, /* north */ 1,-2, 1, -1,-1,-1, 0, 1}; int ge2[11] = { 1, 1, 1, /* northeast */ -1,-2, 1, -1,-1, 1, 0, 1}; int ge3[11] = {-1, 1, 1, /* east */ -1,-2, 1, -1, 1, 1, 0, 1}; int ge4[11] = {-1,-1, 1, /* southeast */ -1,-2, 1, 1, 1, 1, 0, 1}; int ge5[11] = {-1,-1,-1, /* south */ 1,-2, 1, 1, 1, 1, 0, 1}; int ge6[11] = { 1,-1,-1, /* southwest */ 1,-2,-1, 1, 1, 1, 0, 1}; int ge7[11] = { 1, 1,-1, /* west */ 1,-2,-1, 1, 1,-1, 0, 1}; int ge8[11] = { 1, 1, 1, /* northwest */ 1,-2,-1, 1,-1,-1, 0, 1}; int le1[11] = { 0, 1, 0, /* laplace edge */ 1,-4, 1, 0, 1, 0, 0, 1}; int le2[11] = {-1,-1,-1, -1, 8,-1, -1,-1,-1, 0, 1}; int le3[11] = {-1,-1,-1, -1, 9,-1, -1,-1,-1, 0, 1}; int le4[11] = { 1,-2, 1, -2, 4,-2, 1,-2, 1, 0, 1}; int convolve (pras, w, h, opt, kernel, ptrans) uchar_t *pras; register int w; int h; int opt; /* 0=user, 1,2,...=built-in */ int *kernel; /* user kernel, if any */ uchar_t *ptrans; { /* * convolute an image (3x3). return 1 if successful, else 0. * * the basic algorithm is: * * new[i] = sum (k * p ) for i pixels in 3x3 neighborhood * i i */ uchar_t *pr; uchar_t *pt; register int val; register long x; register long y; register uchar_t *ps; register int *pk; pr = pras; pt = ptrans; if (pras != ptrans) { /* * first copy orig image to transform image */ copyrast (pr, w, h, pt); } /* * set pointer to user or built-in kernels, depending on opt */ switch (opt) { case USER_KERN: pk = kernel; break; case LP1_KERN: pk = lp1; break; case LP2_KERN: pk = lp2; break; case LP3_KERN: pk = lp3; break; case HP1_KERN: pk = hp1; break; case HP2_KERN: pk = hp2; break; case HP3_KERN: pk = hp3; break; case SE1_KERN: pk = se1; break; case SE2_KERN: pk = se2; break; case SE3_KERN: pk = se3; break; case GE1_KERN: pk = ge1; break; case GE2_KERN: pk = ge2; break; case GE3_KERN: pk = ge3; break; case GE4_KERN: pk = ge4; break; case GE5_KERN: pk = ge5; break; case GE6_KERN: pk = ge6; break; case GE7_KERN: pk = ge7; break; case GE8_KERN: pk = ge8; break; case LE1_KERN: pk = le1; break; case LE2_KERN: pk = le2; break; case LE3_KERN: pk = le3; break; case LE4_KERN: pk = le4; break; default: return (0); } /* * do it... */ ps = pt; for (y = 1; y < h-1; y++) { for (x = 1; x < w-1; x++) { val = ((uint_t) ps[(y-1)*w+(x-1)]) * pk[0]; val += ((uint_t) ps[(y-1)*w+(x )]) * pk[1]; val += ((uint_t) ps[(y-1)*w+(x+1)]) * pk[2]; val += ((uint_t) ps[(y )*w+(x-1)]) * pk[3]; val += ((uint_t) ps[(y )*w+(x )]) * pk[4]; val += ((uint_t) ps[(y )*w+(x+1)]) * pk[5]; val += ((uint_t) ps[(y+1)*w+(x-1)]) * pk[6]; val += ((uint_t) ps[(y+1)*w+(x )]) * pk[7]; val += ((uint_t) ps[(y+1)*w+(x+1)]) * pk[8]; if ((pk[9] < 0) && pk[10]) val /= pk[10]; else if (pk[9] > 0) val *= pk[10]; if (val < 0) val = 0; else if (val > 255) val = 255; ps[(y*w) + x] = (uchar_t) val; } } return (1); } /*------------------------------*/ /* blur */ /*------------------------------*/ int blur (pras, w, h, ptrans) uchar_t *pras; register int w; int h; uchar_t *ptrans; { /* * blur an image. return 1 if successful, else 0. * * the basic algorithm is: * * new[i] = average of neighboring cells (3x3) */ uchar_t *pr; uchar_t *pt; register long x; register long y; register uchar_t *ps; pr = pras; pt = ptrans; if (pras != ptrans) { /* * first copy orig image to transform image */ copyrast (pr, w, h, pt); } /* * do it... */ ps = pt; for (y = 1; y < h-1; y++) { for (x = 1; x < w-1; x++) { ps[(y*w) + x] = (uchar_t) ( ( (uint_t) ps[(y-1)*w + (x-1)] + (uint_t) ps[(y-1)*w + (x )] + (uint_t) ps[(y-1)*w + (x+1)] + (uint_t) ps[(y )*w + (x-1)] + (uint_t) ps[(y )*w + (x )] + (uint_t) ps[(y )*w + (x+1)] + (uint_t) ps[(y+1)*w + (x-1)] + (uint_t) ps[(y+1)*w + (x )] + (uint_t) ps[(y+1)*w + (x+1)]) / 9); } } return (1); } /*------------------------------*/ /* median */ /*------------------------------*/ int median (pras, w, h, ptrans) uchar_t *pras; int w; int h; uchar_t *ptrans; { /* * median filter an image. return 1 if successful, else 0. * * the basic algorithm is: * * new[i] = median of neighboring cells */ uchar_t *pr; register uchar_t *pt; register long x; register long y; #ifdef INL_SORT register int i; register uint_t a; #endif register uint_t *pl; uint_t l[9]; pr = pras; pt = ptrans; if (pras != ptrans) { /* * first copy orig image to transform image */ copyrast (pr, w, h, pt); } /* * do it... */ pl = l; for (y = 1; y < h-1; y++) { for (x = 1; x < w-1; x++) { pl[0] = (uint_t) pt[(y-1)*w + (x-1)]; pl[1] = (uint_t) pt[(y-1)*w + (x )]; pl[2] = (uint_t) pt[(y-1)*w + (x+1)]; pl[3] = (uint_t) pt[(y )*w + (x-1)]; pl[4] = (uint_t) pt[(y )*w + (x )]; pl[5] = (uint_t) pt[(y )*w + (x+1)]; pl[6] = (uint_t) pt[(y+1)*w + (x-1)]; pl[7] = (uint_t) pt[(y+1)*w + (x )]; pl[8] = (uint_t) pt[(y+1)*w + (x+1)]; #ifdef INL_SORT /* unroll j loop, too... */ for (a=pl[1], i=0; i>=0 && pl[i]>a; i--) pl[i+1]=pl[i]; pl[i+1] = a; for (a=pl[2], i=1; i>=0 && pl[i]>a; i--) pl[i+1]=pl[i]; pl[i+1] = a; for (a=pl[3], i=2; i>=0 && pl[i]>a; i--) pl[i+1]=pl[i]; pl[i+1] = a; for (a=pl[4], i=3; i>=0 && pl[i]>a; i--) pl[i+1]=pl[i]; pl[i+1] = a; for (a=pl[5], i=4; i>=0 && pl[i]>a; i--) pl[i+1]=pl[i]; pl[i+1] = a; for (a=pl[6], i=5; i>=0 && pl[i]>a; i--) pl[i+1]=pl[i]; pl[i+1] = a; for (a=pl[7], i=6; i>=0 && pl[i]>a; i--) pl[i+1]=pl[i]; pl[i+1] = a; for (a=pl[8], i=7; i>=0 && pl[i]>a; i--) pl[i+1]=pl[i]; pl[i+1] = a; #else piksrt (9, l); #endif pt[(y*w) + x] = pl[4]; } } return (1); } /*------------------------------*/ /* piksrt */ /*------------------------------*/ piksrt (num, arr) int num; uint_t *arr; { /* * straight insertion sort (num. rec. in C, pp 243). is N^2 sort, * probably ok for N=9. shell sort is 3x faster for N=9. */ register uint_t *parr; register int n; register int i; register int j; register uint_t a; n = num; parr = arr; for (j = 1; j < n; j++) { for (a=parr[j], i=j-1; i>=0 && parr[i]>a; i--) parr[i+1] = parr[i]; parr[i+1] = a; } } /*------------------------------*/ /* findmedian */ /*------------------------------*/ uint_t findmedian (num, arr) int num; uint_t *arr; { /* * find median of an array of numbers. this should be faster than sort. * there are pathalogical cases: if all are the same or all but 1 or 2 * are the same... */ register uint_t *parr; register int n; register int i; register int j; register int count; register uint_t a; parr = arr; n = num; for (j = 0; j < n; j++) { for (a = parr[j], count = 0, i = 0; i < n; i++) { if (i == j) continue; if (a > parr[i]) count++; } if (count == (n>>1)) return (a); } } /*------------------------------*/ /* logscale */ /*------------------------------*/ int logscale (pras, w, h, ptrans) uchar_t *pras; int w; int h; uchar_t *ptrans; { /* * apply log scaling to an image. return 1 if successful, else 0. * * the basic algorithm is: * * new[i] = maxval * log(old[i]) / log(maxval) * or * new[i] = maxval * log2(old[i]) / log2(maxval) */ uchar_t *pr; uchar_t *pt; register ulong_t maxval; register ulong_t l2maxval; register ulong_t l2pr; uchar_t uctmp; long x; long y; long val; register long ii; register long lim; register uchar_t *ps; pr = pras; pt = ptrans; if (pras != ptrans) { /* * first copy orig image to transform image */ copyrast (pr, w, h, pt); } /* * find maxval. here it is max value a pixel can have, 255. */ #if 1 maxval = 0L; for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { uctmp = pt[(y*w) + x]; if (uctmp > maxval) maxval = (ulong_t) uctmp; } } #endif /*!!! maxval = 255L;*/ /* * do it... */ #if 1 l2maxval = (ulong_t) Log2x10 ((uint_t) maxval); if (l2maxval == 0) return (0); #endif /*!!! l2maxval = 80;*/ /* approx 10 times log2(255) */ #ifdef DBL_LOOP for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { l2pr = (ulong_t) Log2x10 ((uint_t) pt[(y*w)+x]); pt[(y*w) + x] = (uchar_t) ((maxval * l2pr) / l2maxval); } } #else lim = (long) w * (long) h; for (ps = pt, ii = 0L; ii < lim; ii++) { l2pr = (ulong_t) Log2x10 ((uint_t) *ps); *ps++ = (uchar_t) ((maxval * l2pr) / l2maxval); } #endif return (1); } /*------------------------------*/ /* Log2x10 */ /*------------------------------*/ int Log2x10(x) uint_t x; { /* * VERY approximate log base 2 times 10. basically finds MS bit... */ if (x < 256) goto lobyte; if (x & 0x8000) return (150); if (x & 0x4000) return (140); if (x & 0x2000) return (130); if (x & 0x1000) return (120); if (x & 0x0800) return (110); if (x & 0x0400) return (100); if (x & 0x0200) return (90); if (x & 0x0100) return (80); lobyte: if (x == 0x00ff) return (80); if (x == 0x0000) return (1); if (x & 0x0080) { if (x & 0x0040) return (78); else if (x & 0x0020) return (75); else return (71); } if (x & 0x0040) { if (x & 0x0020) return (68); else if (x & 0x0010) return (65); else return (61); } if (x & 0x0020) { if (x & 0x0010) return (58); else if (x & 0x0008) return (55); else return (51); } if (x & 0x0010) { if (x & 0x0008) return (48); else if (x & 0x0004) return (45); else return (41); } if (x & 0x0008) { if (x & 0x0004) return (38); else if (x & 0x0002) return (35); else return (31); } if (x & 0x0004) { if (x & 0x0002) return (28); else if (x & 0x0001) return (25); else return (21); } if (x & 0x0002) { if (x & 0x0001) return (18); else return (13); } if (x & 0x0001) return (10); return (0); } /*------------------------------*/ /* contrast */ /*------------------------------*/ int contrast (pras, w, h, thresh, hist, ptrans) uchar_t *pras; int w; int h; long thresh; long *hist; uchar_t *ptrans; { /* * apply contrast expansion to an image. return 1 if successful, else 0. * * the basic algorithm is: * * new[i] = maxval * (old[i] - lo) / (hi - lo) * * where lo to hi is new contrast range */ uchar_t *pr; uchar_t *pt; ulong_t maxval; uchar_t uctmp; long x; long y; long hi_lo; long newlo; long newhi; int i; register long val; register long rng; register long lim; register long ii; register uchar_t *ps; pr = pras; pt = ptrans; if (pras != ptrans) { /* * first copy orig image to transform image */ copyrast (pr, w, h, pt); } /* * get current histogram... */ if (do_hist (pt, w, h, hist) == 0) return (0); /* * find intensities on either side of hist where pixel count * exceeds thresh */ for (i = 0; i < HISTSIZ; i++) { if (hist[i] > thresh) break; } newlo = i; for (i = HISTSIZ-1; i > newlo; i--) { if (hist[i] > thresh) break; } newhi = i; /* * do it. set pixels below lower threshold 0 and those above to 255. * contrast expand pixels between... */ #ifdef DBL_LOOP rng = newhi - newlo + 1; for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { val = (ulong_t) pt[(y*w) + x]; if (val < newlo) pt[(y*w) + x] = 0; else if (val > newhi) pt[(y*w) + x] = 255; else { pt[(y*w) + x] = (uchar_t) ((255L * (val - newlo)) / rng); } } } #else rng = newhi - newlo + 1; lim = (long) w * (long) h; for (ps = pt, ii = 0L; ii < lim; ii++, ps++) { val = (ulong_t) *ps; if (val < newlo) *ps = 0; else if (val > newhi) *ps = 255; else *ps = (uchar_t) ((255L * (val - newlo)) / rng); } #endif return (1); } /*------------------------------*/ /* brighten */ /*------------------------------*/ int brighten (pras, w, h, brite, ptrans) uchar_t *pras; int w; int h; register int brite; uchar_t *ptrans; { /* * brighten an image. return 1 if successful, else 0. * * the basic algorithm is: * * new[i] = old[i] + brite */ uchar_t *pr; uchar_t *pt; long x; long y; int sign; register uint_t val; register long ii; register long lim; register uchar_t *ps; pr = pras; pt = ptrans; if (pras != ptrans) { /* * first copy orig image to transform image */ copyrast (pr, w, h, pt); } sign = 0; if (brite < 0) { sign = 1; brite = -brite; } /* * do it... */ if (sign) { #ifdef DBL_LOOP for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { val = (uint_t) pt[y*w + x]; if (val < brite) val = 0; else val -= brite; pt[(y*w) + x] = (uchar_t) val; } } #else lim = (long) w * (long) h; for (ps = pt, ii = 0L; ii < lim; ii++, ps++) { if ((uint_t) *ps < brite) *ps = 0; else *ps -= brite; } #endif } else { #ifdef DBL_LOOP for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { val = (uint_t) ((uint_t) pt[y*w + x] + brite); if (val > 255) val = 255; pt[(y*w) + x] = (uchar_t) val; } } #else lim = (long) w * (long) h; for (ps = pt, ii = 0L; ii < lim; ii++, ps++) { val = (uint_t) ((uint_t) *ps + brite); if (val > 255) val = 255; *ps = (uchar_t) val; } #endif } return (1); } /*------------------------------*/ /* invert */ /*------------------------------*/ int invert (pras, w, h, thresh, ptrans) uchar_t *pras; int w; int h; int thresh; uchar_t *ptrans; { /* * invert (negate) an image. return 1 if successful, else 0. * * the basic algorithm is: * * new[i] = 255 - old[i] */ uchar_t *pr; uchar_t *pt; long x; long y; int sign; register long lim; register long ii; register int thr; register uchar_t *ps; pr = pras; pt = ptrans; if (pras != ptrans) { /* * first copy orig image to transform image */ copyrast (pr, w, h, pt); } sign = 0; if (thresh < 0) { sign = 1; thresh = -thresh; } /* * do it... */ #ifdef DBL_LOOP if (thresh == 0) { for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { pt[(y*w) + x] = 255 - pt[(y*w) + x]; } } } else if (sign) { /* * invert only below thresh */ for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { if ((uint_t) pt[(y*w) + x] < thresh) pt[(y*w) + x] = 255 - pt[(y*w) + x]; } } } else { /* * invert only above thresh */ for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { if ((uint_t) pt[(y*w) + x] > thresh) pt[(y*w) + x] = 255 - pt[(y*w) + x]; } } } #else lim = (long) h * (long) w; thr = thresh; if (thr == 0) { for (ps = pt, ii = 0L; ii < lim; ii++, ps++) { *ps = 255 - *ps; } } else if (sign) { /* * invert only below thresh */ for (ps = pt, ii = 0L; ii < lim; ii++, ps++) { if ((uint_t) *ps < thr) *ps = 255 - *ps; } } else { /* * invert above below thresh */ for (ps = pt, ii = 0L; ii < lim; ii++, ps++) { if ((uint_t) *ps > thr) *ps = 255 - *ps; } } #endif return (1); } /*------------------------------*/ /* threshold */ /*------------------------------*/ int threshold (pras, w, h, thresh, ptrans) uchar_t *pras; int w; int h; int thresh; uchar_t *ptrans; { /* * threshold an image. return 1 if successful, else 0. * * the basic algorithm is: * * new[i] = 0 if old[i] <= thresh * new[i] = 255 if old[i] > thresh */ uchar_t *pr; uchar_t *pt; long x; long y; uint_t val; register long ii; register long lim; register uchar_t *ps; pr = pras; pt = ptrans; if (pras != ptrans) { /* * first copy orig image to transform image */ copyrast (pr, w, h, pt); } /* * do it... */ #ifdef DBL_LOOP for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { val = (uint_t) pt[(y*w) + x]; if (val > thresh) pt[(y*w) + x] = 255; else pt[(y*w) + x] = 0; } } #else lim = (long) h * (long) w; for (ps = pt, ii = 0L; ii < lim; ii++, ps++) { if ((uint_t) *ps > thresh) *ps = 255; else *ps = 0; } #endif return (1); } /*------------------------------*/ /* histeq */ /*------------------------------*/ int histeq (pras, w, h, hist, ptrans) uchar_t *pras; int w; int h; long *hist; uchar_t *ptrans; { /* * histogram equalization of image. return 1 if successful, else 0. */ long p_r[HISTSIZ]; long s_k[HISTSIZ]; long s_kapprx[HISTSIZ]; uchar_t *pr; uchar_t *pt; int i; long count; pr = pras; pt = ptrans; if (pras != ptrans) { /* * first copy orig image to transform image */ copyrast (pr, w, h, pt); } /* * get current histogram... */ if (do_hist (pt, w, h, hist) == 0) return (0); /* * find prob density function (p_r), transformation function (s_k), * and new distribution. note the 1000 to avoid floats... */ count = (long) w * (long) h; for (i = 0; i < HISTSIZ; i++) { p_r[i] = (hist[i] * 1000L) / count; } for (s_k[0] = p_r[0], i = 1; i < HISTSIZ; i++) { s_k[i] = s_k[i-1] + p_r[i]; } for (i = 0; i < HISTSIZ; i++) { /* the 500 is for rounding to nearest int... */ s_kapprx[i] = ((s_k[i] * 255L) + 500L) / 1000L; } #if 0 printf ("\n i hist p_r s_k s_kapprx\n"); for (count = 0, i = 0; i < HISTSIZ; i++) { printf ("%5d%10ld%10ld%10ld%10ld\n", i,hist[i],p_r[i],s_k[i],s_kapprx[i]); } #endif /* * now redistribute. s_kapprx will contain the new value for * a given pixel intensity */ redistribute (pt, w, h, s_kapprx); return (1); } /*------------------------------*/ /* redistribute */ /*------------------------------*/ int redistribute (pras, w, h, s_kapprx) uchar_t *pras; int w; int h; register long *s_kapprx; { /* * redistribute pixels. each pixel set to value given by s_kapprx */ register uchar_t *pr; register long ii; register long lim; lim = (long) w * (long) h; for (pr = pras, ii = 0L; ii < lim; ii++, pr++) { *pr = (uchar_t) s_kapprx[(uint_t) *pr]; } } /*------------------------------*/ /* copyrast */ /*------------------------------*/ int copyrast (ps, w, h, pd) uchar_t *ps; /* source */ int w; int h; uchar_t *pd; /* dest */ { /* * copy an image. return 1 if successful, else 0. */ #ifdef DBL_LOOP long x; long y; for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { pd[(y*w) + x] = ps[(y*w) + x]; } } #else register long ii; register long lim; lim = (long) w * (long) h; for (ii = 0L; ii < lim; ii++) *pd++ = *ps++; #endif return (1); }