ilu_scaling.c
Upload User: wmy0603
Upload Date: 2022-05-02
Package Size: 1808k
Code Size: 10k
Development Platform:

Visual C++

  1. // http://www.cse.ucsc.edu/~pang/160/f98/Gems/GemsIII/
  2. /*
  3.  * Filtered Image Rescaling
  4.  *
  5.  *   by Dale Schumacher
  6.  */
  7. #if 0
  8. #include "ilu_internal.h"
  9. char _Copyright[] = "Public Domain 1991 by Dale Schumacher";
  10. #define WHITE_PIXEL (255)
  11. #define BLACK_PIXEL (0)
  12. /*
  13.  * generic image access and i/o support routines
  14.  */
  15. ILubyte get_pixel(ILuint x, ILuint y)
  16. {
  17. Image *im = NULL;
  18. int yy = -1;
  19. Pixel *p = NULL;
  20. if((x < 0) || (x >= image->xsize) || (y < 0) || (y >= image->ysize)) {
  21. return(0);
  22. }
  23. if((im != image) || (yy != y)) {
  24. im = image;
  25. yy = y;
  26. p = image->data + (y * image->span);
  27. }
  28. return(p[x]);
  29. }
  30. void
  31. get_row(row, image, y)
  32. Pixel *row;
  33. Image *image;
  34. int y;
  35. {
  36. if((y < 0) || (y >= image->ysize)) {
  37. return;
  38. }
  39. memcpy(row,
  40. image->data + (y * image->span),
  41. (sizeof(Pixel) * image->xsize));
  42. }
  43. void
  44. get_column(column, image, x)
  45. Pixel *column;
  46. Image *image;
  47. int x;
  48. {
  49. int i, d;
  50. Pixel *p;
  51. if((x < 0) || (x >= image->xsize)) {
  52. return;
  53. }
  54. d = image->span;
  55. for(i = image->ysize, p = image->data + x; i-- > 0; p += d) {
  56. *column++ = *p;
  57. }
  58. }
  59. Pixel
  60. put_pixel(image, x, y, data)
  61. Image *image;
  62. int x, y;
  63. Pixel data;
  64. {
  65. Image *im = NULL;
  66. ILint yy = -1;
  67. Pixel *p = NULL;
  68. if((x < 0) || (x >= image->xsize) || (y < 0) || (y >= image->ysize)) {
  69. return(0);
  70. }
  71. if((im != image) || (yy != y)) {
  72. im = image;
  73. yy = y;
  74. p = image->data + (y * image->span);
  75. }
  76. return(p[x] = data);
  77. }
  78. /*
  79.  * filter function definitions
  80.  */
  81. #define filter_support (1.0)
  82. double filter( double t) {
  83. /* f(t) = 2|t|^3 - 3|t|^2 + 1, -1 <= t <= 1 */
  84. if(t < 0.0) t = -t;
  85. if(t < 1.0) return((2.0 * t - 3.0) * t * t + 1.0);
  86. return(0.0);
  87. }
  88. #define box_support (0.5)
  89. double box_filter( double t) {
  90. if((t > -0.5) && (t <= 0.5)) return(1.0);
  91. return(0.0);
  92. }
  93. #define triangle_support (1.0)
  94. double triangle_filter( double t ) {
  95. if(t < 0.0) t = -t;
  96. if(t < 1.0) return(1.0 - t);
  97. return(0.0);
  98. }
  99. #define bell_support (1.5)
  100. double bell_filter( double t) { /* box (*) box (*) box */
  101. if(t < 0) t = -t;
  102. if(t < .5) return(.75 - (t * t));
  103. if(t < 1.5) {
  104. t = (t - 1.5);
  105. return(.5 * (t * t));
  106. }
  107. return(0.0);
  108. }
  109. #define B_spline_support (2.0)
  110. double
  111. B_spline_filter(t) /* box (*) box (*) box (*) box */
  112. double t;
  113. {
  114. double tt;
  115. if(t < 0) t = -t;
  116. if(t < 1) {
  117. tt = t * t;
  118. return((.5 * tt * t) - tt + (2.0 / 3.0));
  119. } else if(t < 2) {
  120. t = 2 - t;
  121. return((1.0 / 6.0) * (t * t * t));
  122. }
  123. return(0.0);
  124. }
  125. double
  126. sinc(x)
  127. double x;
  128. {
  129. x *= IL_PI;
  130. if(x != 0) return(sin(x) / x);
  131. return(1.0);
  132. }
  133. #define Lanczos3_support (3.0)
  134. double
  135. Lanczos3_filter(t)
  136. double t;
  137. {
  138. if(t < 0) t = -t;
  139. if(t < 3.0) return(sinc(t) * sinc(t/3.0));
  140. return(0.0);
  141. }
  142. #define Mitchell_support (2.0)
  143. #define B (1.0 / 3.0)
  144. #define C (1.0 / 3.0)
  145. double
  146. Mitchell_filter(t)
  147. double t;
  148. {
  149. double tt;
  150. tt = t * t;
  151. if(t < 0) t = -t;
  152. if(t < 1.0) {
  153. t = (((12.0 - 9.0 * B - 6.0 * C) * (t * tt))
  154.    + ((-18.0 + 12.0 * B + 6.0 * C) * tt)
  155.    + (6.0 - 2 * B));
  156. return(t / 6.0);
  157. } else if(t < 2.0) {
  158. t = (((-1.0 * B - 6.0 * C) * (t * tt))
  159.    + ((6.0 * B + 30.0 * C) * tt)
  160.    + ((-12.0 * B - 48.0 * C) * t)
  161.    + (8.0 * B + 24 * C));
  162. return(t / 6.0);
  163. }
  164. return(0.0);
  165. }
  166. /*
  167.  * image rescaling routine
  168.  */
  169. typedef struct {
  170. int pixel;
  171. double weight;
  172. } CONTRIB;
  173. typedef struct {
  174. int n; /* number of contributors */
  175. CONTRIB *p; /* pointer to list of contributions */
  176. } CLIST;
  177. CLIST *contrib; /* array of contribution lists */
  178. void
  179. zoom(dst, src, filterf, fwidth)
  180. Image *dst; /* destination image structure */
  181. Image *src; /* source image structure */
  182. double (*filterf)(); /* filter function */
  183. double fwidth; /* filter width (support) */
  184. {
  185. Image *tmp; /* intermediate image */
  186. double xscale, yscale; /* zoom scale factors */
  187. int i, j, k; /* loop variables */
  188. int n; /* pixel number */
  189. double center, left, right; /* filter calculation variables */
  190. double width, fscale, weight; /* filter calculation variables */
  191. Pixel *raster; /* a row or column of pixels */
  192. /* create intermediate image to hold horizontal zoom */
  193. tmp = new_image(dst->xsize, src->ysize);
  194. xscale = (double) dst->xsize / (double) src->xsize;
  195. yscale = (double) dst->ysize / (double) src->ysize;
  196. /* pre-calculate filter contributions for a row */
  197. contrib = (CLIST*)icalloc(dst->xsize, sizeof(CLIST));
  198. if(xscale < 1.0) {
  199. width = fwidth / xscale;
  200. fscale = 1.0 / xscale;
  201. for(i = 0; i < dst->xsize; ++i) {
  202. contrib[i].n = 0;
  203. contrib[i].p = (CONTRIB*)icalloc((int) (width * 2 + 1),
  204. sizeof(CONTRIB));
  205. center = (double) i / xscale;
  206. left = ceil(center - width);
  207. right = floor(center + width);
  208. for(j = left; j <= right; ++j) {
  209. weight = center - (double) j;
  210. weight = (*filterf)(weight / fscale) / fscale;
  211. if(j < 0) {
  212. n = -j;
  213. } else if(j >= src->xsize) {
  214. n = (src->xsize - j) + src->xsize - 1;
  215. } else {
  216. n = j;
  217. }
  218. k = contrib[i].n++;
  219. contrib[i].p[k].pixel = n;
  220. contrib[i].p[k].weight = weight;
  221. }
  222. }
  223. } else {
  224. for(i = 0; i < dst->xsize; ++i) {
  225. contrib[i].n = 0;
  226. contrib[i].p = (CONTRIB*)icalloc((int) (fwidth * 2 + 1), sizeof(CONTRIB));
  227. center = (double) i / xscale;
  228. left = ceil(center - fwidth);
  229. right = floor(center + fwidth);
  230. for(j = left; j <= right; ++j) {
  231. weight = center - (double) j;
  232. weight = (*filterf)(weight);
  233. if(j < 0) {
  234. n = -j;
  235. } else if(j >= src->xsize) {
  236. n = (src->xsize - j) + src->xsize - 1;
  237. } else {
  238. n = j;
  239. }
  240. k = contrib[i].n++;
  241. contrib[i].p[k].pixel = n;
  242. contrib[i].p[k].weight = weight;
  243. }
  244. }
  245. }
  246. /* apply filter to zoom horizontally from src to tmp */
  247. raster = (Pixel*)icalloc(src->xsize, sizeof(Pixel));
  248. for(k = 0; k < tmp->ysize; ++k) {
  249. get_row(raster, src, k);
  250. for(i = 0; i < tmp->xsize; ++i) {
  251. weight = 0.0;
  252. for(j = 0; j < contrib[i].n; ++j) {
  253. weight += raster[contrib[i].p[j].pixel]
  254. * contrib[i].p[j].weight;
  255. }
  256. put_pixel(tmp, i, k,
  257. (Pixel)CLAMP(weight, BLACK_PIXEL, WHITE_PIXEL));
  258. }
  259. }
  260. ifree(raster);
  261. /* free the memory allocated for horizontal filter weights */
  262. for(i = 0; i < tmp->xsize; ++i) {
  263. ifree(contrib[i].p);
  264. }
  265. ifree(contrib);
  266. /* pre-calculate filter contributions for a column */
  267. contrib = (CLIST*)icalloc(dst->ysize, sizeof(CLIST));
  268. if(yscale < 1.0) {
  269. width = fwidth / yscale;
  270. fscale = 1.0 / yscale;
  271. for(i = 0; i < dst->ysize; ++i) {
  272. contrib[i].n = 0;
  273. contrib[i].p = (CONTRIB*)icalloc((int) (width * 2 + 1), sizeof(CONTRIB));
  274. center = (double) i / yscale;
  275. left = ceil(center - width);
  276. right = floor(center + width);
  277. for(j = left; j <= right; ++j) {
  278. weight = center - (double) j;
  279. weight = (*filterf)(weight / fscale) / fscale;
  280. if(j < 0) {
  281. n = -j;
  282. } else if(j >= tmp->ysize) {
  283. n = (tmp->ysize - j) + tmp->ysize - 1;
  284. } else {
  285. n = j;
  286. }
  287. k = contrib[i].n++;
  288. contrib[i].p[k].pixel = n;
  289. contrib[i].p[k].weight = weight;
  290. }
  291. }
  292. } else {
  293. for(i = 0; i < dst->ysize; ++i) {
  294. contrib[i].n = 0;
  295. contrib[i].p = (CONTRIB*)icalloc((int) (fwidth * 2 + 1),
  296. sizeof(CONTRIB));
  297. center = (double) i / yscale;
  298. left = ceil(center - fwidth);
  299. right = floor(center + fwidth);
  300. for(j = left; j <= right; ++j) {
  301. weight = center - (double) j;
  302. weight = (*filterf)(weight);
  303. if(j < 0) {
  304. n = -j;
  305. } else if(j >= tmp->ysize) {
  306. n = (tmp->ysize - j) + tmp->ysize - 1;
  307. } else {
  308. n = j;
  309. }
  310. k = contrib[i].n++;
  311. contrib[i].p[k].pixel = n;
  312. contrib[i].p[k].weight = weight;
  313. }
  314. }
  315. }
  316. /* apply filter to zoom vertically from tmp to dst */
  317. raster = (Pixel*)icalloc(tmp->ysize, sizeof(Pixel));
  318. for(k = 0; k < dst->xsize; ++k) {
  319. get_column(raster, tmp, k);
  320. for(i = 0; i < dst->ysize; ++i) {
  321. weight = 0.0;
  322. for(j = 0; j < contrib[i].n; ++j) {
  323. weight += raster[contrib[i].p[j].pixel]
  324. * contrib[i].p[j].weight;
  325. }
  326. put_pixel(dst, k, i,
  327. (Pixel)CLAMP(weight, BLACK_PIXEL, WHITE_PIXEL));
  328. }
  329. }
  330. ifree(raster);
  331. /* free the memory allocated for vertical filter weights */
  332. for(i = 0; i < dst->ysize; ++i) {
  333. ifree(contrib[i].p);
  334. }
  335. ifree(contrib);
  336. free_image(tmp);
  337. }
  338. /*
  339.  * command line interface
  340.  */
  341. void
  342. usage()
  343. {
  344. fprintf(stderr, "usage: %s [-options] input.bm output.bmn", _Program);
  345. fprintf(stderr, "
  346. options:n
  347. -x xsize output x sizen
  348. -y ysize output y sizen
  349. -f filter filter typen
  350. {b=box, t=triangle, q=bell, B=B-spline, h=hermite, l=Lanczos3, m=Mitchell}n
  351. ");
  352. exit(1);
  353. }
  354. main(argc, argv)
  355. int argc;
  356. char *argv[];
  357. {
  358. register int c;
  359. int optind;
  360. char *optarg;
  361. int xsize = 0, ysize = 0;
  362. double (*f)() = filter;
  363. double s = filter_support;
  364. char *dstfile, *srcfile;
  365. Image *dst, *src;
  366. FILE *fp;
  367. while((c = getopt(argc, argv, "x:y:f:V")) != EOF) {
  368. switch(c) {
  369. case 'x': xsize = atoi(optarg); break;
  370. case 'y': ysize = atoi(optarg); break;
  371. case 'f':
  372. switch(*optarg) {
  373. case 'b': f=box_filter; s=box_support; break;
  374. case 't': f=triangle_filter; s=triangle_support; break;
  375. case 'q': f=bell_filter; s=bell_support; break;
  376. case 'B': f=B_spline_filter; s=B_spline_support; break;
  377. case 'h': f=filter; s=filter_support; break;
  378. case 'l': f=Lanczos3_filter; s=Lanczos3_support; break;
  379. case 'm': f=Mitchell_filter; s=Mitchell_support; break;
  380. default: usage();
  381. }
  382. break;
  383. case 'V': banner(); exit(EXIT_SUCCESS);
  384. case '?': usage();
  385. default:  usage();
  386. }
  387. }
  388. if((argc - optind) != 2) usage();
  389. srcfile = argv[optind];
  390. dstfile = argv[optind + 1];
  391. if(((fp = fopen(srcfile, "r")) == NULL)
  392. || ((src = load_image(fp)) == NULL)) {
  393. fprintf(stderr, "%s: can't load source image '%s'n",
  394. _Program, srcfile);
  395. exit(EXIT_FAILURE);
  396. }
  397. fclose(fp);
  398. if(xsize <= 0) xsize = src->xsize;
  399. if(ysize <= 0) ysize = src->ysize;
  400. dst = new_image(xsize, ysize);
  401. zoom(dst, src, f, s);
  402. if(((fp = fopen(dstfile, "w")) == NULL)
  403. || (save_image(fp, dst) != 0)) {
  404. fprintf(stderr, "%s: can't save destination image '%s'n",
  405. _Program, dstfile);
  406. exit(EXIT_FAILURE);
  407. }
  408. fclose(fp);
  409. exit(EXIT_SUCCESS);
  410. }
  411. #endif