convolve.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  1. /*
  2. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  3. ;;; File: convolve.c
  4. ;;; Author: Eero Simoncelli
  5. ;;; Description: General convolution code for 2D images
  6. ;;; Creation Date: Spring, 1987.
  7. ;;; MODIFICATIONS:
  8. ;;; 10/89: approximately optimized the choice of register vars on SPARCS.
  9. ;;; 6/96: Switched array types to double float.
  10. ;;; 2/97: made more robust and readable. Added STOP arguments.
  11. ;;; 8/97: Bug: when calling internal_reduce with edges in {reflect1,repeat,
  12. ;;; extend} and an even filter dimension. Solution: embed the filter
  13. ;;; in the upper-left corner of a filter with odd Y and X dimensions.
  14. ;;; ----------------------------------------------------------------
  15. ;;; Object-Based Vision and Image Understanding System (OBVIUS),
  16. ;;; Copyright 1988, Vision Science Group, Media Laboratory,
  17. ;;; Massachusetts Institute of Technology.
  18. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  19. */
  20. #include <stdio.h>
  21. #include <math.h>
  22. #include "convolve.h"
  23. /*
  24. --------------------------------------------------------------------
  25. Correlate FILT with IMAGE, subsampling according to START, STEP, and
  26. STOP parameters, with values placed into RESULT array. RESULT
  27. dimensions should be ceil((stop-start)/step). TEMP should be a
  28. pointer to a temporary double array the size of the filter.
  29. EDGES is a string specifying how to handle boundaries -- see edges.c.
  30. The convolution is done in 9 sections, where the border sections use
  31. specially computed edge-handling filters (see edges.c). The origin
  32. of the filter is assumed to be (floor(x_fdim/2), floor(y_fdim/2)).
  33. ------------------------------------------------------------------------ */
  34. /* abstract out the inner product computation */
  35. #define INPROD(XCNR,YCNR) \
  36. { \
  37. sum=0.0; \
  38. for (im_pos=YCNR*x_dim+XCNR, filt_pos=0, x_filt_stop=x_fdim; \
  39. x_filt_stop<=filt_size; \
  40. im_pos+=(x_dim-x_fdim), x_filt_stop+=x_fdim) \
  41. for (; \
  42. filt_pos<x_filt_stop; \
  43. filt_pos++, im_pos++) \
  44. sum+= image[im_pos]*temp[filt_pos]; \
  45. result[res_pos] = sum; \
  46. }
  47. int internal_reduce(image, x_dim, y_dim, filt, temp, x_fdim, y_fdim,
  48. x_start, x_step, x_stop, y_start, y_step, y_stop,
  49. result, edges)
  50. register image_type *image, *temp;
  51. register int x_fdim, x_dim;
  52. register image_type *result;
  53. register int x_step, y_step;
  54. int x_start, y_start;
  55. int x_stop, y_stop;
  56. image_type *filt;
  57. int y_dim, y_fdim;
  58. char *edges;
  59. {
  60. register double sum;
  61. register int filt_pos, im_pos, x_filt_stop;
  62. register int x_pos, filt_size = x_fdim*y_fdim;
  63. register int y_pos, res_pos;
  64. register int y_ctr_stop = y_dim - ((y_fdim==1)?0:y_fdim);
  65. register int x_ctr_stop = x_dim - ((x_fdim==1)?0:x_fdim);
  66. register int x_res_dim = (x_stop-x_start+x_step-1)/x_step;
  67. int x_ctr_start = ((x_fdim==1)?0:1);
  68. int y_ctr_start = ((y_fdim==1)?0:1);
  69. int x_fmid = x_fdim/2;
  70. int y_fmid = y_fdim/2;
  71. int base_res_pos;
  72. fptr reflect = edge_function(edges); /* look up edge-handling function */
  73. if (!reflect) return(-1);
  74. /* shift start/stop coords to filter upper left hand corner */
  75. x_start -= x_fmid; y_start -= y_fmid;
  76. x_stop -= x_fmid; y_stop -= y_fmid;
  77. if (x_stop < x_ctr_stop) x_ctr_stop = x_stop;
  78. if (y_stop < y_ctr_stop) y_ctr_stop = y_stop;
  79. for (res_pos=0, y_pos=y_start; /* TOP ROWS */
  80. y_pos<y_ctr_start;
  81. y_pos+=y_step)
  82. {
  83. for (x_pos=x_start; /* TOP-LEFT CORNER */
  84. x_pos<x_ctr_start;
  85. x_pos+=x_step, res_pos++)
  86. {
  87. (*reflect)(filt,x_fdim,y_fdim,x_pos-1,y_pos-1,temp,REDUCE);
  88. INPROD(0,0)
  89. }
  90. (*reflect)(filt,x_fdim,y_fdim,0,y_pos-1,temp,REDUCE);
  91. for (; /* TOP EDGE */
  92. x_pos<x_ctr_stop;
  93. x_pos+=x_step, res_pos++)
  94. INPROD(x_pos,0)
  95. for (; /* TOP-RIGHT CORNER */
  96. x_pos<x_stop;
  97. x_pos+=x_step, res_pos++)
  98. {
  99. (*reflect)(filt,x_fdim,y_fdim,x_pos-x_ctr_stop+1,y_pos-1,temp,REDUCE);
  100. INPROD(x_ctr_stop,0)
  101. }
  102. } /* end TOP ROWS */
  103. y_ctr_start = y_pos; /* hold location of top */
  104. for (base_res_pos=res_pos, x_pos=x_start; /* LEFT EDGE */
  105. x_pos<x_ctr_start;
  106. x_pos+=x_step, base_res_pos++)
  107. {
  108. (*reflect)(filt,x_fdim,y_fdim,x_pos-1,0,temp,REDUCE);
  109. for (y_pos=y_ctr_start, res_pos=base_res_pos;
  110. y_pos<y_ctr_stop;
  111. y_pos+=y_step, res_pos+=x_res_dim)
  112. INPROD(0,y_pos)
  113. }
  114. (*reflect)(filt,x_fdim,y_fdim,0,0,temp,REDUCE);
  115. for (; /* CENTER */
  116. x_pos<x_ctr_stop;
  117. x_pos+=x_step, base_res_pos++)
  118. for (y_pos=y_ctr_start, res_pos=base_res_pos;
  119. y_pos<y_ctr_stop;
  120. y_pos+=y_step, res_pos+=x_res_dim)
  121. INPROD(x_pos,y_pos)
  122. for (; /* RIGHT EDGE */
  123. x_pos<x_stop;
  124. x_pos+=x_step, base_res_pos++)
  125. {
  126. (*reflect)(filt,x_fdim,y_fdim,x_pos-x_ctr_stop+1,0,temp,REDUCE);
  127. for (y_pos=y_ctr_start, res_pos=base_res_pos;
  128. y_pos<y_ctr_stop;
  129. y_pos+=y_step, res_pos+=x_res_dim)
  130. INPROD(x_ctr_stop,y_pos)
  131. }
  132. for (res_pos-=(x_res_dim-1);
  133. y_pos<y_stop; /* BOTTOM ROWS */
  134. y_pos+=y_step)
  135. {
  136. for (x_pos=x_start; /* BOTTOM-LEFT CORNER */
  137. x_pos<x_ctr_start;
  138. x_pos+=x_step, res_pos++)
  139. {
  140. (*reflect)(filt,x_fdim,y_fdim,x_pos-1,y_pos-y_ctr_stop+1,temp,REDUCE);
  141. INPROD(0,y_ctr_stop)
  142. }
  143. (*reflect)(filt,x_fdim,y_fdim,0,y_pos-y_ctr_stop+1,temp,REDUCE);
  144. for (; /* BOTTOM EDGE */
  145. x_pos<x_ctr_stop;
  146. x_pos+=x_step, res_pos++)
  147. INPROD(x_pos,y_ctr_stop)
  148. for (; /* BOTTOM-RIGHT CORNER */
  149. x_pos<x_stop;
  150. x_pos+=x_step, res_pos++)
  151. {
  152. (*reflect)(filt,x_fdim,y_fdim,x_pos-x_ctr_stop+1,y_pos-y_ctr_stop+1,temp,REDUCE);
  153. INPROD(x_ctr_stop,y_ctr_stop)
  154. }
  155. } /* end BOTTOM */
  156. return(0);
  157. } /* end of internal_reduce */
  158. /*
  159. --------------------------------------------------------------------
  160. Upsample IMAGE according to START,STEP, and STOP parameters and then
  161. convolve with FILT, adding values into RESULT array. IMAGE
  162. dimensions should be ceil((stop-start)/step). See
  163. description of internal_reduce (above).
  164. WARNING: this subroutine destructively modifies the RESULT array!
  165. ------------------------------------------------------------------------ */
  166. /* abstract out the inner product computation */
  167. #define INPROD2(XCNR,YCNR) \
  168. { \
  169. val = image[im_pos]; \
  170. for (res_pos=YCNR*x_dim+XCNR, filt_pos=0, x_filt_stop=x_fdim; \
  171. x_filt_stop<=filt_size; \
  172. res_pos+=(x_dim-x_fdim), x_filt_stop+=x_fdim) \
  173. for (; \
  174. filt_pos<x_filt_stop; \
  175. filt_pos++, res_pos++) \
  176. result[res_pos] += val*temp[filt_pos]; \
  177. }
  178. int internal_expand(image,filt,temp,x_fdim,y_fdim,
  179. x_start,x_step,x_stop,y_start,y_step,y_stop,
  180. result,x_dim,y_dim,edges)
  181. register image_type *result, *temp;
  182. register int x_fdim, x_dim;
  183. register int x_step, y_step;
  184. register image_type *image;
  185. int x_start, y_start;
  186. image_type *filt;
  187. int y_fdim, y_dim;
  188. char *edges;
  189. {
  190. register double val;
  191. register int filt_pos, res_pos, x_filt_stop;
  192. register int x_pos, filt_size = x_fdim*y_fdim;
  193. register int y_pos, im_pos;
  194. register int x_ctr_stop = x_dim - ((x_fdim==1)?0:x_fdim);
  195. int y_ctr_stop = (y_dim - ((y_fdim==1)?0:y_fdim));
  196. int x_ctr_start = ((x_fdim==1)?0:1);
  197. int y_ctr_start = ((y_fdim==1)?0:1);
  198. int x_fmid = x_fdim/2;
  199. int y_fmid = y_fdim/2;
  200. int base_im_pos, x_im_dim = (x_stop-x_start+x_step-1)/x_step;
  201. fptr reflect = edge_function(edges); /* look up edge-handling function */
  202. if (!reflect) return(-1);
  203. /* shift start/stop coords to filter upper left hand corner */
  204. x_start -= x_fmid; y_start -= y_fmid;
  205. x_stop -= x_fmid; y_stop -= y_fmid;
  206. if (x_stop < x_ctr_stop) x_ctr_stop = x_stop;
  207. if (y_stop < y_ctr_stop) y_ctr_stop = y_stop;
  208. for (im_pos=0, y_pos=y_start; /* TOP ROWS */
  209. y_pos<y_ctr_start;
  210. y_pos+=y_step)
  211. {
  212. for (x_pos=x_start; /* TOP-LEFT CORNER */
  213. x_pos<x_ctr_start;
  214. x_pos+=x_step, im_pos++)
  215. {
  216. (*reflect)(filt,x_fdim,y_fdim,x_pos-1,y_pos-1,temp,EXPAND);
  217. INPROD2(0,0)
  218. }
  219. (*reflect)(filt,x_fdim,y_fdim,0,y_pos-1,temp,EXPAND);
  220. for (; /* TOP EDGE */
  221. x_pos<x_ctr_stop;
  222. x_pos+=x_step, im_pos++)
  223. INPROD2(x_pos,0)
  224. for (; /* TOP-RIGHT CORNER */
  225. x_pos<x_stop;
  226. x_pos+=x_step, im_pos++)
  227. {
  228. (*reflect)(filt,x_fdim,y_fdim,x_pos-x_ctr_stop+1,y_pos-1,temp,EXPAND);
  229. INPROD2(x_ctr_stop,0)
  230. }
  231. } /* end TOP ROWS */
  232. y_ctr_start = y_pos; /* hold location of top */
  233. for (base_im_pos=im_pos, x_pos=x_start; /* LEFT EDGE */
  234. x_pos<x_ctr_start;
  235. x_pos+=x_step, base_im_pos++)
  236. {
  237. (*reflect)(filt,x_fdim,y_fdim,x_pos-1,0,temp,EXPAND);
  238. for (y_pos=y_ctr_start, im_pos=base_im_pos;
  239. y_pos<y_ctr_stop;
  240. y_pos+=y_step, im_pos+=x_im_dim)
  241. INPROD2(0,y_pos)
  242. }
  243. (*reflect)(filt,x_fdim,y_fdim,0,0,temp,EXPAND);
  244. for (; /* CENTER */
  245. x_pos<x_ctr_stop;
  246. x_pos+=x_step, base_im_pos++)
  247. for (y_pos=y_ctr_start, im_pos=base_im_pos;
  248. y_pos<y_ctr_stop;
  249. y_pos+=y_step, im_pos+=x_im_dim)
  250. INPROD2(x_pos,y_pos)
  251. for (; /* RIGHT EDGE */
  252. x_pos<x_stop;
  253. x_pos+=x_step, base_im_pos++)
  254. {
  255. (*reflect)(filt,x_fdim,y_fdim,x_pos-x_ctr_stop+1,0,temp,EXPAND);
  256. for (y_pos=y_ctr_start, im_pos=base_im_pos;
  257. y_pos<y_ctr_stop;
  258. y_pos+=y_step, im_pos+=x_im_dim)
  259. INPROD2(x_ctr_stop,y_pos)
  260. }
  261. for (im_pos-=(x_im_dim-1);
  262. y_pos<y_stop; /* BOTTOM ROWS */
  263. y_pos+=y_step)
  264. {
  265. for (x_pos=x_start; /* BOTTOM-LEFT CORNER */
  266. x_pos<x_ctr_start;
  267. x_pos+=x_step, im_pos++)
  268. {
  269. (*reflect)(filt,x_fdim,y_fdim,x_pos-1,y_pos-y_ctr_stop+1,temp,EXPAND);
  270. INPROD2(0,y_ctr_stop)
  271. }
  272. (*reflect)(filt,x_fdim,y_fdim,0,y_pos-y_ctr_stop+1,temp,EXPAND);
  273. for (; /* BOTTOM EDGE */
  274. x_pos<x_ctr_stop;
  275. x_pos+=x_step, im_pos++)
  276. INPROD2(x_pos,y_ctr_stop)
  277. for (; /* BOTTOM-RIGHT CORNER */
  278. x_pos<x_stop;
  279. x_pos+=x_step, im_pos++)
  280. {
  281. (*reflect)(filt,x_fdim,y_fdim,x_pos-x_ctr_stop+1,y_pos-y_ctr_stop+1,temp,EXPAND);
  282. INPROD2(x_ctr_stop,y_ctr_stop)
  283. }
  284. } /* end BOTTOM */
  285. return(0);
  286. } /* end of internal_expand */
  287. /* Local Variables: */
  288. /* buffer-read-only: t */
  289. /* End: */