contrib/tbl/vipl/filter/vipl_filter_helper.h
Go to the documentation of this file.
00001 #ifndef vipl_filter_helper_h_
00002 #define vipl_filter_helper_h_
00003 
00004 typedef unsigned int VIPL_FILTER_STATE;
00005 // the following is defined in vipl_filter.h
00006 //extern const VIPL_FILTER_STATE Not_Ready;
00007 //extern const VIPL_FILTER_STATE Ready;
00008 //extern const VIPL_FILTER_STATE Unchanged;
00009 //extern const VIPL_FILTER_STATE Filter_Owned;
00010 #define READY(x) (x & Ready)
00011 #define NOT_READY(x) (!(x & Ready))
00012 #define UNCHANGED(x) (x & Unchanged)
00013 #define CHANGED(x) (!(x & Unchanged))
00014 #define USER_OWNED(x) (!(x & Filter_Owned))
00015 #define FILTER_OWNED(x) (x & Filter_Owned)
00016 #define NOT(x) (!x)
00017 
00018 // In order to support filtering where the destination section has different
00019 // starting coordinates, the following macros need to be updated
00020 // MASK_CONV, HORIZ_CONV and VERTI_CONV are the actual macros that implement
00021 // the filtering operations - they, as well as the macros that call these will
00022 // need to be modified to support non-uniform section filtering.
00023 // these macros are defined HERE because two separate subclasses branches of
00024 // this ABS filter class use them unmodified.
00025 // These macros do not use any pointer arithmetic, so they are nowhere near as
00026 // efficient as filters can be. A particular bottleneck is all the 2-D
00027 // operator() calls that the convolutions make.  Chances are the filterable
00028 // objects use a multiply-add to implement operator(). (ouch!)
00029 
00030 #define FILL(X1, Y1, X2, Y2, DST, FV) do {\
00031   for (int y = (Y1); y < (Y2); ++y) {\
00032     for (int x = (X1); x < (X2); ++x) {\
00033       SET_PIXEL((DST),x, y, (FV));\
00034     }\
00035   }\
00036 } while (false)
00037 
00038 #define MASK_CONV(X1, Y1, X2, Y2, DELTA_X, DELTA_Y, SRC, DST, KERN) do {\
00039   KernType val;\
00040   vcl_clock_t ct = clock(),ct1;\
00041   for (int y = (Y1); y < (Y2); ++y)\
00042     for (int x = (X1) ; x < (X2); ++x) {\
00043       val = 0.0;\
00044       int je = (KERN).y_end(); int ie = (KERN).x_end();\
00045       for (int j = (KERN).y_start(), jj=y+j; j < je; ++j) {\
00046         for (int i = (KERN).x_start(), ii=x+i; i < ie; ++i)\
00047         val += ((KERN) (i, j) * FGET_PIXEL((SRC), ii++, jj));\
00048         ++jj;\
00049         FSET_PIXEL((DST), x, y, (CONVERT_TO_OUT(val)));\
00050       }\
00051     }\
00052   ct1 = clock();\
00053 } while (false)
00054 
00055 #define MASK_CONV_BOARDER(X1, Y1, X2, Y2, DELTA_X, DELTA_Y, SRC, DST, KERN) \
00056   do {\
00057   KernType val;\
00058   vcl_clock_t ct = clock(),ct1;\
00059   for (int y = (Y1); y < (Y2); ++y)\
00060     for (int x = (X1) ; x < (X2); ++x) {\
00061       val = 0.0;\
00062       int je = (KERN).y_end(); int ie = (KERN).x_end();\
00063       for (int j = (KERN).y_start(), jj=y+j; j < je; ++j) {\
00064         for (int i = (KERN).x_start(), ii=x+i; i < ie; ++i)\
00065         val += ((KERN) (i, j) * GET_PIXEL((SRC), ii++, jj));\
00066         ++jj;\
00067         SET_PIXEL((DST), x, y, (CONVERT_TO_OUT(val)));\
00068       }\
00069     }\
00070   ct1 = clock();\
00071 } while (false)
00072 
00073 #define NORMAL_INTERMEDIATE
00074 #ifdef NORMAL_INTERMEDIATE
00075 
00076 // extern int over, under;
00077 
00078 #define HORIZ_CONV(X1, Y1, X2, Y2, DELTA_X, DELTA_Y, SRC, DST, KERN) do {\
00079   vcl_clock_t ct = clock();\
00080   KernType val;\
00081   for (int y = ((Y1) ); y < ((Y2) ); ++y) {\
00082     for (int x = ((X1) ); x < ((X2) ); ++x) {\
00083       val = 0.0;\
00084       for (int i = (KERN).kernel_start(0),j=i+x; i < (KERN).kernel_end(0); ++i) \
00085         val += ((KERN)(i) * FGET_PIXEL((SRC),j++, y));\
00086       FSET_PIXEL((DST),x, y, (CONVERT_TO_OUT(val)));\
00087     }\
00088   }\
00089   vcl_clock_t ct2= clock();\
00090 } while (false)
00091 
00092 #define HORIZ_CONV_BOARDER(X1, Y1, X2, Y2, DELTA_X, DELTA_Y, SRC, DST, KERN) do {\
00093   vcl_clock_t ct = clock();\
00094   KernType val;\
00095   for (int y = ((Y1) ); y < ((Y2) ); ++y) {\
00096     for (int x = ((X1) ); x < ((X2) ); ++x) {\
00097       val = 0.0;\
00098       for (int i = (KERN).kernel_start(0),j=i+x; i < (KERN).kernel_end(0); ++i) \
00099         val += ((KERN)(i) * GET_PIXEL((SRC),j++, y));\
00100       SET_PIXEL((DST),x, y, (CONVERT_TO_OUT(val)));\
00101     }\
00102   }\
00103   vcl_clock_t ct2= clock();\
00104 } while (false)
00105 
00106 #define VERTI_CONV(X1, Y1, X2, Y2, DELTA_X, DELTA_Y, SRC, DST, KERN) do {\
00107   KernType val;\
00108   vcl_clock_t ct = clock();\
00109   for (int x = ((X1) ); x < ((X2) ); ++x) {\
00110     for (int y = ((Y1) ); y < ((Y2) ); ++y) {\
00111       val = 0;\
00112       for (int i = (KERN).kernel_start(0), j =y+i; i < (KERN).kernel_end(0); ++i)\
00113         val += ((KERN)(i) * FGET_PIXEL((SRC),x, j++));\
00114       FSET_PIXEL((DST),x, y, (CONVERT_TO_OUT(val)));\
00115     }\
00116   }\
00117   vcl_clock_t ct2= clock();\
00118 } while (false)
00119 
00120 #define VERTI_CONV_BOARDER(X1, Y1, X2, Y2, DELTA_X, DELTA_Y, SRC, DST, KERN) do {\
00121   KernType val;\
00122   vcl_clock_t ct = clock();\
00123   for (int x = ((X1) ); x < ((X2) ); ++x) {\
00124     for (int y = ((Y1) ); y < ((Y2) ); ++y) {\
00125       val = 0;\
00126       for (int i = (KERN).kernel_start(0), j =y+i; i < (KERN).kernel_end(0); ++i)\
00127         val += ((KERN)(i) * GET_PIXEL((SRC),x, j++));\
00128       SET_PIXEL((DST),x, y, (CONVERT_TO_OUT(val)));\
00129     }\
00130   }\
00131   vcl_clock_t ct2= clock();\
00132 } while (false)
00133 
00134 #else //else we flip intermediate
00135 
00136 #define HORIZ_CONV(X1, Y1, X2, Y2, DELTA_X, DELTA_Y, SRC, DST, KERN) do {\
00137   KernType val;\
00138   vcl_clock_t ct = clock();\
00139   for (int y = ((Y1) + DELTA_Y); y < ((Y2) - (DELTA_Y)); ++y) {\
00140     for (int x = ((X1) + (DELTA_X)); x < ((X2) - (DELTA_X)); ++x) {\
00141       val = 0.0;\
00142       for (int i = (KERN).kernel_start(0); i < (KERN).kernel_end(0); ++i) \
00143         val += ((KERN) (i) * FGET_PIXEL((SRC), x+i,y));\
00144       FSET_PIXEL((DST), y,x, (CONVERT_TO_OUT(val)));\
00145     }\
00146   }\
00147   vcl_clock_t ct2= clock();\
00148 } while (false)
00149 
00150 #define HORIZ_CONV_BOARDER(X1, Y1, X2, Y2, DELTA_X, DELTA_Y, SRC, DST, KERN) \ do {\
00151   KernType val;\
00152   vcl_clock_t ct = clock();\
00153   for (int y = ((Y1) + DELTA_Y); y < ((Y2) - (DELTA_Y)); ++y) {\
00154     for (int x = ((X1) + (DELTA_X)); x < ((X2) - (DELTA_X)); ++x) {\
00155       val = 0.0;\
00156       for (int i = (KERN).kernel_start(0); i < (KERN).kernel_end(0); ++i) \
00157         val += ((KERN) (i) * GET_PIXEL((SRC), x+i,y));\
00158       SET_PIXEL((DST), y,x, (CONVERT_TO_OUT(val)));\
00159     }\
00160   }\
00161   vcl_clock_t ct2= clock();\
00162 } while (false)
00163 
00164 #define VERTI_CONV(X1, Y1, X2, Y2, DELTA_X, DELTA_Y, SRC, DST, KERN)
00165    do {\
00166   KernType val;\
00167   vcl_clock_t ct = clock();\
00168   for (int x = ((X1) + (DELTA_X)); x < ((X2) - (DELTA_X)); ++x) {\
00169     for (int y = ((Y1) + (DELTA_Y)); y < ((Y2) - (DELTA_Y)); ++y) {\
00170       val = 0;\
00171       for (int i = (KERN).kernel_start(0); i < (KERN).kernel_end(0); ++i)\
00172         val += ((KERN) (i) * FGET_PIXEL((SRC),y+i,x));\
00173       FSET_PIXEL((DST),x, y, (CONVERT_TO_OUT(val)));\
00174     }\
00175   }\
00176   vcl_clock_t ct2= clock();\
00177 } while (false)
00178 
00179 #define VERTI_CONV_BOARDER(X1, Y1, X2, Y2, DELTA_X, DELTA_Y, SRC, DST, KERN)\ do {\
00180   KernType val;\
00181   vcl_clock_t ct = clock();\
00182   for (int x = ((X1) + (DELTA_X)); x < ((X2) - (DELTA_X)); ++x) {\
00183     for (int y = ((Y1) + (DELTA_Y)); y < ((Y2) - (DELTA_Y)); ++y) {\
00184       val = 0;\
00185       for (int i = (KERN).kernel_start(0); i < (KERN).kernel_end(0); ++i)\
00186         val += ((KERN) (i) * GET_PIXEL((SRC),y+i,x));\
00187       SET_PIXEL((DST),x, y, (CONVERT_TO_OUT(val)));\
00188     }\
00189   }\
00190   vcl_clock_t ct2= clock();\
00191 } while (false)
00192 
00193 #endif
00194 
00195 // convolve the top strip from left edge of section to right edge of section
00196 // for Top,Bot,Left,Right, the initial coordinates are for filling the borders
00197 // Ok here is the logic
00198 
00199 #define IMB_LEFT(D,C) ((D).curr_sec_start(X_Axis()) == (C).image_start(X_Axis()))
00200 #define IMB_RIGHT(D,C) ((D).curr_sec_end(X_Axis()) == (C).image_end(X_Axis()))
00201 #define IMB_TOP(D,C) ((D).curr_sec_end(Y_Axis()) == (C).image_end(Y_Axis()))
00202 #define IMB_BOTTOM(D,C) ((D).curr_sec_start(Y_Axis()) == (C).image_start(Y_Axis()))
00203 
00204 // the macro CONVOL_PREAMBLE is for use in an another macro to define useful values
00205 // section start and end coordinates - short
00206 
00207 #define CONVOL_PREAMBLE(CONTAINER, DESCRIPTOR) \
00208   const vipl_section_container<DataTypeOut> &C=(CONTAINER);\
00209   const vipl_section_descriptor<DataTypeOut> &D=(DESCRIPTOR);\
00210   int border = 0;\
00211   const int ibs = image_border_size();\
00212   const int d0 = ibs;\
00213   const int bdr = ibs;\
00214   const DataTypeOut fv = def_fill_value();\
00215   int xcs[4], ycs[4], xce[4], yce[4];\
00216   int do_fill[4]; \
00217   const int XS = D.curr_sec_start(X_Axis()), YS = D.curr_sec_start(Y_Axis());\
00218   const int XE = D.curr_sec_end(X_Axis()), YE = D.curr_sec_end(Y_Axis());\
00219   do_fill[0] = do_fill[1] = do_fill[2] = do_fill[3] = false
00220 
00221 #define CALC_BORDER(B, D, C) (B) = 0; \
00222   if (IMB_LEFT((D), (C))) (B) |= 1;\
00223   if (IMB_TOP((D), (C))) (B) |= 2;\
00224   if (IMB_RIGHT((D), (C))) (B) |= 4;\
00225   if (IMB_BOTTOM((D), (C))) (B) |= 8;
00226 
00227 // the next 4 are for quick "border" comparisons.
00228 
00229 #define IMB_L (1)
00230 #define IMB_T (2)
00231 #define IMB_R (4)
00232 #define IMB_B (8)
00233 
00234 // for use in both preop and postop
00235 
00236 #define CHECK_START_AND_END_FILL(CONTAINER) \
00237     if ((CONTAINER).image_start(Y_Axis()) > ycs[tmpi]){ ycs[tmpi] = (CONTAINER).image_start(Y_Axis()); }\
00238     if ((CONTAINER).image_start(X_Axis()) > xcs[tmpi]){ xcs[tmpi] = (CONTAINER).image_start(X_Axis()); }\
00239     if ((CONTAINER).image_start(Y_Axis()) > yce[tmpi]){ yce[tmpi] = (CONTAINER).image_start(Y_Axis()); }\
00240     if ((CONTAINER).image_start(X_Axis()) > xce[tmpi]){ xce[tmpi] = (CONTAINER).image_start(X_Axis()); }\
00241     if ((CONTAINER).image_end(Y_Axis()) < ycs[tmpi]){ ycs[tmpi] = (CONTAINER).image_end(Y_Axis()); }\
00242     if ((CONTAINER).image_end(X_Axis()) < xcs[tmpi]){ xcs[tmpi] = (CONTAINER).image_end(X_Axis()); }\
00243     if ((CONTAINER).image_end(Y_Axis()) < yce[tmpi]){ yce[tmpi] = (CONTAINER).image_end(Y_Axis()); }\
00244     if ((CONTAINER).image_end(X_Axis()) < xce[tmpi]){ xce[tmpi] = (CONTAINER).image_end(X_Axis()); }
00245 #define CHECK_START_AND_END_OPERATION(CONTAINER) \
00246     if ((CONTAINER).image_start(Y_Axis()) + ibs > ycs[tmpi]){ ycs[tmpi] = (CONTAINER).image_start(Y_Axis()) +ibs; }\
00247     if ((CONTAINER).image_start(X_Axis()) +ibs> xcs[tmpi]){ xcs[tmpi] = (CONTAINER).image_start(X_Axis())+ibs; }\
00248     if ((CONTAINER).image_start(Y_Axis()) +ibs > yce[tmpi]){ yce[tmpi] = (CONTAINER).image_start(Y_Axis()) +ibs; }\
00249     if ((CONTAINER).image_start(X_Axis()) +ibs > xce[tmpi]){ xce[tmpi] = (CONTAINER).image_start(X_Axis()) +ibs; }\
00250     if ((CONTAINER).image_end(Y_Axis()) -ibs < ycs[tmpi]){ ycs[tmpi] = (CONTAINER).image_end(Y_Axis()) -ibs; }\
00251     if ((CONTAINER).image_end(X_Axis())-ibs < xcs[tmpi]){ xcs[tmpi] = (CONTAINER).image_end(X_Axis()) -ibs; }\
00252     if ((CONTAINER).image_end(Y_Axis())-ibs < yce[tmpi]){ yce[tmpi] = (CONTAINER).image_end(Y_Axis()) -ibs; }\
00253     if ((CONTAINER).image_end(X_Axis())-ibs < xce[tmpi]){ xce[tmpi] = (CONTAINER).image_end(X_Axis()) -ibs; }
00254 
00255 // there is a striking similarity between the macros DO_PREOP and
00256 // DO_POSTOP. However, in order to reduce it to one macro, it will need to
00257 // take a LOT of arguments, and even more confusing to the eye. therefore I
00258 // will keep the two macros separate
00259 
00260 #define DO_PREOP(OPERATION, DESCRIPTOR, CONTAINER, SRC, DST, KERN) do {\
00261   CONVOL_PREAMBLE(CONTAINER, DESCRIPTOR);\
00262   CALC_BORDER(border, DESCRIPTOR, CONTAINER);\
00263   if (border & (IMB_L|IMB_B)) {\
00264     do_fill[0] = true;\
00265     xcs[0] = XS; ycs[0] = YS;\
00266     xce[0] = XS + ibs; yce[0] = YS + ibs;\
00267   } else {\
00268     xcs[0] = XS; ycs[0] = YS;\
00269     xce[0] = XS + bdr; yce[0] = YS + bdr;\
00270   }\
00271   if (border & (IMB_B)) {\
00272     do_fill[1] = true; \
00273     xcs[1] = XS + ibs; ycs[1] = YS;\
00274     xce[1] = XE - ibs; yce[1] = YS + ibs;\
00275   } else {\
00276     xcs[1] = XS + bdr; ycs[1] = YS;\
00277     xce[1] = XE - bdr; yce[1] = YS + bdr;\
00278   } \
00279   if (border & (IMB_B|IMB_R)) {\
00280     do_fill[2] = true;\
00281     xcs[2] = XE - ibs; ycs[2] = YS;\
00282     xce[2] = XE; yce[2] = YS + ibs;\
00283   } else {\
00284     xcs[2] = XE - bdr; ycs[2] = YS;\
00285     xce[2] = XE; yce[2] = YS + bdr;\
00286   }\
00287   if (border & IMB_L) {\
00288     do_fill[3] = true;\
00289     xcs[3] = XS; ycs[3] = YS + ibs;\
00290     xce[3] = XS + ibs; yce[3] = YE - ibs;\
00291   } else {\
00292     xcs[3] = XS; ycs[3] = YS + bdr;\
00293     xce[3] = XS + bdr; yce[3] = YE - bdr;\
00294   }\
00295   for (int tmpi = 0; tmpi < 4; ++tmpi) {\
00296     if (do_fill[tmpi]) {\
00297       CHECK_START_AND_END_FILL(CONTAINER) \
00298       handle_image_border(tmpi+1, xcs[tmpi], ycs[tmpi], xce[tmpi], yce[tmpi]);}\
00299     else {\
00300       CHECK_START_AND_END_OPERATION(CONTAINER) \
00301       OPERATION(xcs[tmpi], ycs[tmpi], xce[tmpi], yce[tmpi], 0, 0, SRC, DST, KERN);}\
00302   }\
00303 } while (false)
00304 
00305 // the macro DO_POSTOP shares many structural similarities with DO_PREOP, but
00306 // to avoid 3 dozen macro arguments as well as for the sake of a slightly more
00307 // readable macro form, I decide to keep them separate
00308 
00309 #define DO_POSTOP(OPERATION, DESCRIPTOR, CONTAINER, SRC, DST, KERN) do {\
00310   CONVOL_PREAMBLE(CONTAINER, DESCRIPTOR);\
00311   CALC_BORDER(border, DESCRIPTOR, CONTAINER);\
00312   if (border & IMB_R) {\
00313     do_fill[0] = true;\
00314     xcs[0] = XE - ibs; ycs[0] = YS + ibs;\
00315     xce[0] = XE; yce[0] = YE - ibs;\
00316   } else {\
00317     xcs[0] = XE - bdr; ycs[0] = YS + bdr;\
00318     xce[0] = XE; yce[0] = YE - bdr;\
00319   }\
00320   if (border & (IMB_L|IMB_T)) {\
00321     do_fill[1] = true; \
00322     xcs[1] = XS; ycs[1] = YE - ibs;\
00323     xce[1] = XS + ibs; yce[1] = YE;\
00324   } else {\
00325     xcs[1] = XS; ycs[1] = YE - bdr;\
00326     xce[1] = XS + bdr; yce[1] = YE;\
00327   } \
00328   if (border & IMB_T) {\
00329     do_fill[2] = true;\
00330     xcs[2] = XS + ibs; ycs[2] = YE - ibs;\
00331     xce[2] = XE - ibs; yce[2] = YE;\
00332   } else {\
00333     xcs[2] = XS + bdr; ycs[2] = YE - bdr;\
00334     xce[2] = XE - bdr; yce[2] = YE;\
00335   }\
00336   if (border & (IMB_T|IMB_R)) {\
00337     do_fill[3] = true;\
00338     xcs[3] = XE - ibs; ycs[3] = YE - ibs;\
00339     xce[3] = XE; yce[3] = YE;\
00340   } else {\
00341     xcs[3] = XE - bdr; ycs[3] = YE - bdr;\
00342     xce[3] = XE; yce[3] = YE;\
00343   }\
00344   for (int tmpi = 0; tmpi < 4; ++tmpi) {\
00345     if (do_fill[tmpi]) {\
00346       CHECK_START_AND_END_FILL(CONTAINER) \
00347       handle_image_border(tmpi+6, xcs[tmpi], ycs[tmpi], xce[tmpi], yce[tmpi]);}\
00348     else {\
00349       CHECK_START_AND_END_OPERATION(CONTAINER) \
00350       OPERATION(xcs[tmpi], ycs[tmpi], xce[tmpi], yce[tmpi], 0, 0, SRC, DST, KERN);}\
00351   }\
00352 } while (false)
00353 
00354 #endif