00001 /*!@file ModelNeuron/NeuralLayer.C Class implementation of neural weights*/ 00002 00003 // //////////////////////////////////////////////////////////////////// // 00004 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2001 by the // 00005 // University of Southern California (USC) and the iLab at USC. // 00006 // See http://iLab.usc.edu for information about this project. // 00007 // //////////////////////////////////////////////////////////////////// // 00008 // Major portions of the iLab Neuromorphic Vision Toolkit are protected // 00009 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency // 00010 // in Visual Environments, and Applications'' by Christof Koch and // 00011 // Laurent Itti, California Institute of Technology, 2001 (patent // 00012 // pending; application number 09/912,225 filed July 23, 2001; see // 00013 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status). // 00014 // //////////////////////////////////////////////////////////////////// // 00015 // This file is part of the iLab Neuromorphic Vision C++ Toolkit. // 00016 // // 00017 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can // 00018 // redistribute it and/or modify it under the terms of the GNU General // 00019 // Public License as published by the Free Software Foundation; either // 00020 // version 2 of the License, or (at your option) any later version. // 00021 // // 00022 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope // 00023 // that it will be useful, but WITHOUT ANY WARRANTY; without even the // 00024 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // 00025 // PURPOSE. See the GNU General Public License for more details. // 00026 // // 00027 // You should have received a copy of the GNU General Public License // 00028 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write // 00029 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, // 00030 // Boston, MA 02111-1307 USA. // 00031 // //////////////////////////////////////////////////////////////////// // 00032 // 00033 // Primary maintainer for this file: David Berg <dberg@usc.edu> 00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/ModelNeuron/Weights.C $ 00035 00036 #include "Image/Kernels.H" 00037 #include "Image/MathOps.H" 00038 #include "Image/LowPass.H" 00039 #include "Image/LowPassLpt.H" 00040 00041 #include "ModelNeuron/Weights.H" 00042 00043 // ###################################################################### 00044 // Copies from filtering routines from Image/ but with type modifications 00045 // ###################################################################### 00046 namespace WeightFilter 00047 { 00048 //copies from Convolutions.H but for type double 00049 Image<double> 00050 convolveHmax(const Image<double>& src, const Image<double>& filter) 00051 { 00052 ASSERT(src.initialized()); 00053 const int Nx = filter.getWidth(), Ny = filter.getHeight(); 00054 ASSERT((Nx & 1) && (Ny & 1)); 00055 00056 const int w = src.getWidth(), h = src.getHeight(); 00057 00058 Image<double> result(w, h, NO_INIT); 00059 Image<double>::const_iterator sptr = src.begin(); 00060 Image<double>::iterator dptr = result.beginw(); 00061 Image<double>::const_iterator const filt = filter.begin(); 00062 00063 int kkk = Nx * Ny - 1; 00064 int Nx2 = (Nx - 1) / 2, Ny2 = (Ny - 1) / 2; 00065 // very inefficient implementation; one has to be crazy to use non 00066 // separable filters anyway... 00067 for (int j = 0; j < h; ++j) 00068 for (int i = 0; i < w; ++i) 00069 { 00070 double sum = 0.0, sumw = 0.0; 00071 for (int kj = 0; kj < Ny; ++kj) 00072 { 00073 int kjj = kj + j - Ny2; 00074 if (kjj >= 0 && kjj < h) 00075 for (int ki = 0; ki < Nx; ++ki) 00076 { 00077 int kii = ki + i - Nx2; 00078 if (kii >= 0 && kii < w) 00079 { 00080 double fil = filt[kkk - ki - Nx*kj]; 00081 double img = sptr[kii + w * kjj]; 00082 sum += img * fil; sumw += img * img; 00083 } 00084 } 00085 } 00086 //if (sumw > 0.0F) sum /= fastSqrt(sumw); 00087 if (sumw > 0.0) sum = fabs(sum)/sqrt(sumw); 00088 *dptr++ = sum; 00089 } 00090 return result; 00091 } 00092 00093 // ###################################################################### 00094 Image<double> 00095 optConvolve(const Image<double>& src, const Image<double>& f) 00096 { 00097 ASSERT(src.initialized()); 00098 00099 const int src_w = src.getWidth(); 00100 const int src_h = src.getHeight(); 00101 00102 Image<double>::const_iterator filter = f.begin(); 00103 const int fil_w = f.getWidth(); 00104 const int fil_h = f.getHeight(); 00105 00106 ASSERT((fil_w & 1) && (fil_h & 1)); 00107 00108 Image<double> result(src_w, src_h, NO_INIT); 00109 Image<double>::const_iterator sptr = src.begin(); 00110 Image<double>::iterator dptr = result.beginw(); 00111 00112 const int fil_end = fil_w * fil_h - 1; 00113 const int Nx2 = (fil_w - 1) / 2; 00114 const int Ny2 = (fil_h - 1) / 2; 00115 00116 const int srow_skip = src_w-fil_w; 00117 00118 for (int dst_y = 0; dst_y < src_h; ++dst_y) 00119 { 00120 // Determine if we're safely inside the image in the y-direction: 00121 const bool y_clean = dst_y >= Ny2 && dst_y < (src_h - Nx2); 00122 00123 for (int dst_x = 0; dst_x < src_w; ++dst_x, ++dptr) 00124 { 00125 // Determine if we're safely inside the image in the x-direction: 00126 const bool x_clean = dst_x >= Nx2 && dst_x < (src_w - Nx2); 00127 00128 // Here is where we pick whether we can use the optimized inner 00129 // loop (in cases where the filter and image patch overlap 00130 // completely) or whether we must use the inner loop that can 00131 // handle boundary conditions. 00132 00133 if (x_clean && y_clean) 00134 { 00135 double dst_val = 0.0; 00136 00137 Image<double>::const_iterator fptr = filter+fil_end; 00138 00139 Image<double>::const_iterator srow_ptr = 00140 sptr + src_w*(dst_y-Nx2) + dst_x - Nx2; 00141 00142 for (int f_y = 0; f_y < fil_h; ++f_y) 00143 { 00144 for (int f_x = 0; f_x < fil_w; ++f_x) 00145 dst_val += (*srow_ptr++) * (*fptr--); 00146 00147 srow_ptr += srow_skip; 00148 } 00149 *dptr = dst_val; 00150 continue; 00151 } 00152 else 00153 { 00154 // OK, we're at an image boundary, so what do we do to make 00155 // up for the missing pixels? The approach here is to 00156 // compute the average value of the non-missing pixels, and 00157 // proceed as if the missing pixels had that value. This 00158 // minimizes the introduction of edge artifacts e.g. when 00159 // convolving with an oriented filter. 00160 00161 double dst_val = 0.0; 00162 double src_sum = 0.0; 00163 int src_cnt = 0; 00164 double fil_sum_skipped = 0.0; 00165 00166 for (int f_y = 0; f_y < fil_h; ++f_y) 00167 { 00168 const int src_y = f_y + dst_y - Ny2; 00169 if (src_y >= 0 && src_y < src_h) 00170 { 00171 for (int f_x = 0; f_x < fil_w; ++f_x) 00172 { 00173 const double fil = filter[fil_end - f_x - fil_w*f_y]; 00174 00175 const int src_x = f_x + dst_x - Nx2; 00176 if (src_x >= 0 && src_x < src_w) 00177 { 00178 const double src_val = sptr[src_x + src_w * src_y]; 00179 dst_val += src_val * fil; 00180 src_sum += src_val; 00181 ++src_cnt; 00182 } 00183 else 00184 { 00185 fil_sum_skipped += fil; 00186 } 00187 } 00188 } 00189 else 00190 { 00191 for (int f_x = 0; f_x < fil_w; ++f_x) 00192 fil_sum_skipped += filter[fil_end - f_x - fil_w*f_y]; 00193 } 00194 } 00195 const double src_avg = src_sum / src_cnt; 00196 *dptr = dst_val + (fil_sum_skipped * src_avg); 00197 } 00198 } 00199 } 00200 return result; 00201 } 00202 00203 // ###################################################################### 00204 static Image<double> 00205 xFilter(const Image<double>& src, const double* hFilt, const int hfs, 00206 ConvolutionBoundaryStrategy boundary) 00207 { 00208 const int w = src.getWidth(), h = src.getHeight(); 00209 00210 if (hfs == 0) return src; // no filter 00211 Image<double> result(w, h, NO_INIT); 00212 Image<double>::const_iterator sptr = src.begin(); 00213 Image<double>::iterator dptr = result.beginw(); 00214 00215 const int hfs2 = (hfs - 1) / 2; 00216 00217 // flip the filter to accelerate convolution: 00218 double *hFilter = new double[hfs]; double sumh = 0.0; 00219 for (int x = 0; x < hfs; x ++) 00220 { sumh += hFilt[x]; hFilter[hfs-1-x] = hFilt[x]; } 00221 00222 // *** horizontal pass *** 00223 if (w < hfs) // special function for very small images 00224 { 00225 switch (boundary) 00226 { 00227 case CONV_BOUNDARY_ZERO: 00228 { 00229 for (int j = 0; j < h; j ++) 00230 for (int i = 0; i < w; i ++) 00231 { 00232 double val = 0; 00233 for (int k = 0; k < hfs; k ++) 00234 if (i + k - hfs2 >= 0 && i + k - hfs2 < w) 00235 { 00236 val += sptr[k - hfs2] * hFilter[k]; 00237 } 00238 *dptr++ = val; sptr ++; 00239 } 00240 } 00241 break; 00242 case CONV_BOUNDARY_CLEAN: 00243 { 00244 for (int j = 0; j < h; j ++) 00245 for (int i = 0; i < w; i ++) 00246 { 00247 double val = 0.0; double sum = 0.0; 00248 for (int k = 0; k < hfs; k ++) 00249 if (i + k - hfs2 >= 0 && i + k - hfs2 < w) 00250 { 00251 val += sptr[k - hfs2] * hFilter[k]; 00252 sum += hFilter[k]; 00253 } 00254 *dptr++ = val * sumh / sum; sptr ++; 00255 } 00256 } 00257 break; 00258 case CONV_BOUNDARY_REPLICATE: 00259 { 00260 for (int j = 0; j < h; j ++) 00261 for (int i = 0; i < w; i ++) 00262 { 00263 double val = 0.0; 00264 for (int k = 0; k < hfs; k ++) 00265 if (i + k - hfs2 < 0) 00266 { 00267 val += sptr[-i] * hFilter[k]; 00268 } 00269 else if (i + k - hfs2 >= w) 00270 { 00271 val += sptr[w-1-i] * hFilter[k]; 00272 } 00273 else 00274 { 00275 val += sptr[k - hfs2] * hFilter[k]; 00276 } 00277 *dptr++ = val; sptr ++; 00278 } 00279 } 00280 break; 00281 default: 00282 LFATAL("invalid convolution boundary strategy %d", 00283 (int) boundary); 00284 } 00285 } 00286 else // function for reasonably large images 00287 for (int jj = 0; jj < h; jj ++) 00288 { 00289 // leftmost points: 00290 switch (boundary) 00291 { 00292 case CONV_BOUNDARY_ZERO: 00293 { 00294 for (int j = hfs2; j > 0; --j) 00295 { 00296 double val = 0.0; 00297 for (int k = j; k < hfs; ++k) 00298 { 00299 val += sptr[k - j] * hFilter[k]; 00300 } 00301 *dptr++ = val; 00302 } 00303 } 00304 break; 00305 case CONV_BOUNDARY_CLEAN: 00306 { 00307 for (int j = hfs2; j > 0; --j) 00308 { 00309 double val = 0.0; double sum = 0.0; 00310 for (int k = j; k < hfs; ++k) 00311 { 00312 val += sptr[k - j] * hFilter[k]; 00313 sum += hFilter[k]; 00314 } 00315 *dptr++ = val * sumh / sum; 00316 } 00317 } 00318 break; 00319 case CONV_BOUNDARY_REPLICATE: 00320 { 00321 for (int j = hfs2; j > 0; --j) 00322 { 00323 double val = 0.0; 00324 for (int k = 0; k < j; ++k) 00325 { 00326 val += sptr[0] * hFilter[k]; 00327 } 00328 for (int k = j; k < hfs; ++k) 00329 { 00330 val += sptr[k - j] * hFilter[k]; 00331 } 00332 *dptr++ = val; 00333 } 00334 } 00335 break; 00336 default: 00337 LFATAL("invalid convolution boundary strategy %d", 00338 (int) boundary); 00339 } 00340 // bulk (far from the borders): 00341 for (int i = 0; i < w - hfs + 1; i ++) 00342 { 00343 double val = 0.0; 00344 for (int k = 0; k < hfs; k ++) val += sptr[k] * hFilter[k]; 00345 *dptr++ = val; sptr++; 00346 } 00347 // rightmost points: 00348 switch (boundary) 00349 { 00350 case CONV_BOUNDARY_ZERO: 00351 { 00352 for (int j = hfs - 1; j > hfs2; --j) 00353 { 00354 double val = 0.0; 00355 for (int k = 0; k < j; ++k) 00356 { 00357 val += sptr[k] * hFilter[k]; 00358 } 00359 *dptr++ = val; 00360 sptr++; 00361 } 00362 } 00363 break; 00364 case CONV_BOUNDARY_CLEAN: 00365 { 00366 for (int j = hfs - 1; j > hfs2; --j) 00367 { 00368 double val = 0.0; double sum = 0.0; 00369 for (int k = 0; k < j; ++k) 00370 { 00371 val += sptr[k] * hFilter[k]; 00372 sum += hFilter[k]; 00373 } 00374 *dptr++ = val * sumh / sum; 00375 sptr++; 00376 } 00377 } 00378 break; 00379 case CONV_BOUNDARY_REPLICATE: 00380 { 00381 for (int j = hfs - 1; j > hfs2; --j) 00382 { 00383 double val = 0.0; 00384 for (int k = 0; k < j; ++k) 00385 { 00386 val += sptr[k] * hFilter[k]; 00387 } 00388 for (int k = j; k < hfs; ++k) 00389 { 00390 val += sptr[j-1] * hFilter[k]; 00391 } 00392 *dptr++ = val; 00393 sptr++; 00394 } 00395 } 00396 break; 00397 default: 00398 LFATAL("invalid convolution boundary strategy %d", 00399 (int) boundary); 00400 } 00401 sptr += hfs2; // sptr back to same as dptr (start of next line) 00402 } 00403 delete [] hFilter; 00404 return result; 00405 } 00406 00407 // ###################################################################### 00408 static Image<double> 00409 yFilter(const Image<double>& src, const double* vFilt, const int vfs, 00410 ConvolutionBoundaryStrategy boundary) 00411 { 00412 const int w = src.getWidth(), h = src.getHeight(); 00413 00414 if (vfs == 0) return src; // no filter 00415 Image<double> result(w, h, NO_INIT); 00416 Image<double>::const_iterator sptr = src.begin(); 00417 Image<double>::iterator dptr = result.beginw(); 00418 00419 const int vfs2 = (vfs - 1) / 2; 00420 00421 // flip the filter to accelerate convolution: 00422 double *vFilter = new double[vfs]; double sumv = 0.0; 00423 for (int x = 0; x < vfs; x ++) 00424 { sumv += vFilt[x]; vFilter[vfs-1-x] = vFilt[x]; } 00425 00426 int ww[vfs]; 00427 for (int i = 0; i < vfs; i ++) ww[i] = w * i; // speedup precompute 00428 00429 if (h < vfs) // special function for very small images 00430 { 00431 switch (boundary) 00432 { 00433 case CONV_BOUNDARY_ZERO: 00434 { 00435 for (int j = 0; j < h; j ++) 00436 for (int i = 0; i < w; i ++) 00437 { 00438 double val = 0.0; 00439 for (int k = 0; k < vfs; k ++) 00440 if (j + k - vfs2 >= 0 && j + k - vfs2 < h) 00441 { 00442 val += sptr[w * (k - vfs2)] * vFilter[k]; 00443 } 00444 *dptr++ = val; sptr ++; 00445 } 00446 } 00447 break; 00448 case CONV_BOUNDARY_CLEAN: 00449 { 00450 for (int j = 0; j < h; j ++) 00451 for (int i = 0; i < w; i ++) 00452 { 00453 double val = 0.0; double sum = 0.0; 00454 for (int k = 0; k < vfs; k ++) 00455 if (j + k - vfs2 >= 0 && j + k - vfs2 < h) 00456 { 00457 val += sptr[w * (k - vfs2)] * vFilter[k]; 00458 sum += vFilter[k]; 00459 } 00460 *dptr++ = val * sumv / sum; sptr ++; 00461 } 00462 } 00463 break; 00464 case CONV_BOUNDARY_REPLICATE: 00465 { 00466 for (int j = 0; j < h; j ++) 00467 for (int i = 0; i < w; i ++) 00468 { 00469 double val = 0.0; 00470 for (int k = 0; k < vfs; k ++) 00471 if (j + k - vfs2 < 0) 00472 { 00473 val += sptr[w * (-j)] * vFilter[k]; 00474 } 00475 else if (j + k - vfs2 >= h) 00476 { 00477 val += sptr[w * (h-1-j)] * vFilter[k]; 00478 } 00479 else 00480 { 00481 val += sptr[w * (k - vfs2)] * vFilter[k]; 00482 } 00483 *dptr++ = val; sptr ++; 00484 } 00485 } 00486 break; 00487 default: 00488 LFATAL("invalid convolution boundary strategy %d", 00489 (int) boundary); 00490 } 00491 } 00492 else // function for reasonably large images 00493 { 00494 // top points: 00495 switch (boundary) 00496 { 00497 case CONV_BOUNDARY_ZERO: 00498 { 00499 for (int j = vfs2; j > 0; --j) 00500 { 00501 for (int i = 0; i < w; ++i) // scan all points of given horiz 00502 { 00503 double val = 0.0; 00504 for (int k = j; k < vfs; ++k) 00505 { 00506 val += sptr[ww[k - j]] * vFilter[k]; 00507 } 00508 *dptr++ = val; 00509 sptr++; 00510 } 00511 sptr -= w; // back to top-left corner 00512 } 00513 } 00514 break; 00515 case CONV_BOUNDARY_CLEAN: 00516 { 00517 for (int j = vfs2; j > 0; --j) 00518 { 00519 for (int i = 0; i < w; ++i) // scan all points of given horiz 00520 { 00521 double val = 0.0; double sum = 0.0; 00522 for (int k = j; k < vfs; ++k) 00523 { 00524 val += sptr[ww[k - j]] * vFilter[k]; 00525 sum += vFilter[k]; 00526 } 00527 *dptr++ = val * sumv / sum; 00528 sptr++; 00529 } 00530 sptr -= w; // back to top-left corner 00531 } 00532 } 00533 break; 00534 case CONV_BOUNDARY_REPLICATE: 00535 { 00536 for (int j = vfs2; j > 0; --j) 00537 { 00538 for (int i = 0; i < w; ++i) // scan all points of given horiz 00539 { 00540 double val = 0.0; 00541 for (int k = 0; k < j; ++k) 00542 { 00543 val += sptr[ww[0]] * vFilter[k]; 00544 } 00545 for (int k = j; k < vfs; ++k) 00546 { 00547 val += sptr[ww[k - j]] * vFilter[k]; 00548 } 00549 *dptr++ = val; 00550 sptr++; 00551 } 00552 sptr -= w; // back to top-left corner 00553 } 00554 } 00555 break; 00556 default: 00557 LFATAL("invalid convolution boundary strategy %d", 00558 (int) boundary); 00559 } 00560 // bulk (far from edges): 00561 for (int j = 0; j < h - vfs + 1; j ++) 00562 for (int i = 0; i < w; i ++) 00563 { 00564 double val = 0.0; 00565 for (int k = 0; k < vfs; k ++) val += sptr[ww[k]] * vFilter[k]; 00566 *dptr++ = val; sptr ++; 00567 } 00568 // bottommost points: 00569 switch (boundary) 00570 { 00571 case CONV_BOUNDARY_ZERO: 00572 { 00573 for (int j = vfs - 1; j > vfs2; --j) 00574 for (int i = 0; i < w; ++i) 00575 { 00576 double val = 0.0; 00577 for (int k = 0; k < j; ++k) 00578 { 00579 val += sptr[ww[k]] * vFilter[k]; 00580 } 00581 *dptr++ = val; 00582 sptr ++; 00583 } 00584 } 00585 break; 00586 case CONV_BOUNDARY_CLEAN: 00587 { 00588 for (int j = vfs - 1; j > vfs2; --j) 00589 for (int i = 0; i < w; ++i) 00590 { 00591 double val = 0.0; double sum = 0.0; 00592 for (int k = 0; k < j; ++k) 00593 { 00594 val += sptr[ww[k]] * vFilter[k]; 00595 sum += vFilter[k]; 00596 } 00597 *dptr++ = val * sumv / sum; 00598 sptr ++; 00599 } 00600 } 00601 break; 00602 case CONV_BOUNDARY_REPLICATE: 00603 { 00604 for (int j = vfs - 1; j > vfs2; --j) 00605 for (int i = 0; i < w; ++i) 00606 { 00607 double val = 0.0; 00608 for (int k = 0; k < j; ++k) 00609 { 00610 val += sptr[ww[k]] * vFilter[k]; 00611 } 00612 for (int k = j; k < vfs; ++k) 00613 { 00614 val += sptr[ww[j-1]] * vFilter[k]; 00615 } 00616 *dptr++ = val; 00617 sptr ++; 00618 } 00619 } 00620 break; 00621 default: 00622 LFATAL("invalid convolution boundary strategy %d", 00623 (int) boundary); 00624 } 00625 } 00626 delete [] vFilter; 00627 return result; 00628 } 00629 00630 // ###################################################################### 00631 Image<double> 00632 sepFilter(const Image<double>& src, const Image<double>& hFilter, 00633 const Image<double>& vFilter, 00634 ConvolutionBoundaryStrategy boundary) 00635 { 00636 ASSERT(hFilter.is1D() || hFilter.getSize() == 0); 00637 ASSERT(vFilter.is1D() || vFilter.getSize() == 0); 00638 00639 Image<double> result = src; 00640 const int hfs = hFilter.getSize(); 00641 const int vfs = vFilter.getSize(); 00642 if (hfs > 0) result = xFilter(result, hFilter.getArrayPtr(), 00643 hfs, boundary); 00644 if (vfs > 0) result = yFilter(result, vFilter.getArrayPtr(), 00645 vfs, boundary); 00646 00647 return result; 00648 } 00649 }//end namespace WeightFilter 00650 00651 // ###################################################################### 00652 // WeightsAll implementation 00653 // ###################################################################### 00654 WeightsAll::WeightsAll() : WeightsDerived<WeightsAll>(), itsW(0.0) { }; 00655 00656 // ###################################################################### 00657 WeightsAll::WeightsAll(const double& weight) : WeightsDerived<WeightsAll>(), 00658 itsW(weight) { itsInit = true; } 00659 00660 // ###################################################################### 00661 Image<double> WeightsAll::compute(const Image<double>& in) 00662 { 00663 double s = sum(in); 00664 s *= itsW; 00665 Image<double> out(in.getDims(), NO_INIT); 00666 out.clear(s); 00667 return out; 00668 } 00669 00670 // ###################################################################### 00671 // WeightsUniform implementation 00672 // ###################################################################### 00673 WeightsUniform::WeightsUniform() : WeightsDerived<WeightsUniform>(), itsW(0.0) { }; 00674 00675 // ###################################################################### 00676 WeightsUniform::WeightsUniform(const double& weight) : WeightsDerived<WeightsUniform>(), itsW(weight) 00677 { itsInit = true; } 00678 00679 // ###################################################################### 00680 Image<double> WeightsUniform::compute(const Image<double>& in) 00681 { 00682 Image<double> out = in * itsW; 00683 return out; 00684 } 00685 00686 // ###################################################################### 00687 // WeightsBinomial implementation 00688 // ###################################################################### 00689 WeightsBinomial::WeightsBinomial() : WeightsDerived<WeightsBinomial>(), 00690 itsTaps(0), itsIter(0), subCenter(false), 00691 itsCenter(0.0), itsWeight(0.0), 00692 itsBp(NONE), itsSetup(false) { }; 00693 00694 // ###################################################################### 00695 WeightsBinomial::WeightsBinomial(const double& std, const double& weight, 00696 const bool doSubCenter, const BorderPolicy bp, 00697 const uint taps) : 00698 itsTaps(taps), itsIter(0), subCenter(doSubCenter), itsCenter(0.0), 00699 itsWeight(weight), itsBp(bp), itsSetup(false) 00700 { 00701 //get required iterations 00702 itsIter = uint((std*std) / (double(taps - 1)/4.0)); 00703 itsInit = true; 00704 } 00705 00706 // ###################################################################### 00707 Image<double> WeightsBinomial::compute(const Image<double>& in) 00708 { 00709 Image<double> out = in; 00710 if (!itsSetup) 00711 { 00712 Image<double> impulse(in.getDims(), ZEROS); 00713 uint cx = (uint) (in.getWidth() / 2) - 1; 00714 uint cy = (uint) (in.getHeight() / 2) - 1; 00715 impulse.setVal(cx, cy, 1.0); 00716 impulse = filterBinomial(impulse,itsIter, itsTaps, itsBp); 00717 itsCenter = 1.0 / impulse.getVal(cx,cy); 00718 if (!subCenter) 00719 itsCenter*= itsWeight; 00720 00721 itsSetup = true; 00722 } 00723 00724 //do the filtering 00725 out = filterBinomial(out, itsIter, itsTaps, itsBp); 00726 00727 //subtract energy from self excitation, then scale 00728 if (subCenter) 00729 { 00730 out *= itsCenter; 00731 out -= in; 00732 out *= itsWeight; 00733 } 00734 else 00735 out *= itsCenter; 00736 00737 return out; 00738 } 00739 00740 // ###################################################################### 00741 // WeightsCS implementation 00742 // ###################################################################### 00743 WeightsCS::WeightsCS() : WeightsDerived<WeightsCS>(), itsW(0.0, 0.0, false, NONE, 0), 00744 itsInh(0.0) { }; 00745 00746 // ###################################################################### 00747 WeightsCS::WeightsCS(const double& estd, const double& eweight, 00748 const double& inhibit, const bool doSubCenter, 00749 const BorderPolicy bp, const uint taps) : 00750 WeightsDerived<WeightsCS>(), itsW(estd, eweight, doSubCenter, bp, taps), itsInh(inhibit) 00751 { itsInit = true; } 00752 00753 // ###################################################################### 00754 Image<double> WeightsCS::compute(const Image<double>& in) 00755 { 00756 Image<double> e = itsW.compute(in); 00757 const double s = sum(in) * itsInh; 00758 e -= s; 00759 return e; 00760 } 00761 00762 // ###################################################################### 00763 // WeightsDoG implementation 00764 // ###################################################################### 00765 WeightsDoG::WeightsDoG() : WeightsDerived<WeightsDoG>(), itsE(0.0, 0.0, false, NONE, 0), 00766 itsI(0.0, 0.0, false, NONE, 0) { }; 00767 00768 // ###################################################################### 00769 WeightsDoG::WeightsDoG(const double& estd, const double& istd, 00770 const double& ew, const double& iw, 00771 const bool subCenter, const BorderPolicy bp, 00772 const uint taps) : WeightsDerived<WeightsDoG>(), 00773 itsE(estd, ew, subCenter, bp, taps), 00774 itsI(istd, iw, subCenter, bp, taps) 00775 { 00776 itsInit = true; 00777 } 00778 00779 // ###################################################################### 00780 Image<double> WeightsDoG::compute(const Image<double>& in) 00781 { 00782 Image<double> e = itsE.compute(in); 00783 const Image<double> i = itsI.compute(in); 00784 e -= i; 00785 return e; 00786 } 00787 00788 // ###################################################################### 00789 // Weights1D implementation 00790 // ###################################################################### 00791 Weights1D::Weights1D() : WeightsDerived<Weights1D>(), subCenter(false), itsCenter(0.0), 00792 itsStrat(CONV_BOUNDARY_CLEAN), itsX(), itsY(), 00793 itsSetup(false) { } 00794 00795 // ###################################################################### 00796 Weights1D::Weights1D(const bool doSubCenter, 00797 const ConvolutionBoundaryStrategy strat) : 00798 WeightsDerived<Weights1D>(), 00799 subCenter(doSubCenter), itsCenter(0.0), itsStrat(strat), 00800 itsX(), itsY(), itsSetup(false) { } 00801 00802 // ###################################################################### 00803 void Weights1D::addWeight(const Image<double>& wxy) 00804 { 00805 itsX.push_back(wxy); 00806 itsY.push_back(wxy); 00807 itsInit = true; 00808 } 00809 00810 // ###################################################################### 00811 void Weights1D::addWeight(const Image<double>& wx, const Image<double>& wy) 00812 { 00813 itsX.push_back(wx); 00814 itsY.push_back(wy); 00815 itsInit = true; 00816 } 00817 00818 // ###################################################################### 00819 void Weights1D::clear() 00820 { 00821 itsX.clear(); 00822 itsY.clear(); 00823 itsCenter = 0.0; 00824 itsSetup = false; 00825 } 00826 00827 // ###################################################################### 00828 Image<double> Weights1D::compute(const Image<double>& in) 00829 { 00830 00831 if (~itsSetup && subCenter) 00832 { 00833 Image<double> impulse(in.getDims(), ZEROS); 00834 uint cx = (uint) (in.getWidth() / 2) - 1; 00835 uint cy = (uint) (in.getHeight() / 2) - 1; 00836 impulse.setVal(cx, cy, 1.0); 00837 //filter to get response at center 00838 for (uint jj = 0; jj < itsX.size(); ++jj) 00839 impulse = WeightFilter::sepFilter(impulse,itsX[jj],itsY[jj],itsStrat); 00840 itsCenter = impulse.getVal(cx,cy); 00841 itsSetup = true; 00842 } 00843 00844 Image<double> out = in; 00845 //apply the filter bank 00846 for (uint jj = 0; jj < itsX.size(); ++jj) 00847 out = WeightFilter::sepFilter(out, itsX[jj], itsY[jj], itsStrat); 00848 00849 //subtract energy from self excitation 00850 if (subCenter) 00851 out = out - (in * itsCenter); 00852 00853 return out; 00854 } 00855 00856 // ###################################################################### 00857 // Weights2D implementation 00858 // ###################################################################### 00859 Weights2D::Weights2D(const ConvolutionBoundaryStrategy strat) 00860 : WeightsDerived<Weights2D>(), itsStrat(strat), itsW() 00861 { 00862 } 00863 00864 // ###################################################################### 00865 void Weights2D::addWeight(const Image<double>& w) 00866 { 00867 if (w.is1D()) 00868 LFATAL("Filter needs to be 2D for this Weights type"); 00869 else 00870 itsW.push_back(w); 00871 itsInit = true; 00872 } 00873 00874 // ###################################################################### 00875 void Weights2D::clear() 00876 { 00877 itsW.clear(); 00878 itsInit = false; 00879 } 00880 00881 // ###################################################################### 00882 Image<double> Weights2D::compute(const Image<double>& in) 00883 { 00884 Image<double> out = in; 00885 //apply the filter bank itsIter iterations 00886 if (itsStrat == CONV_BOUNDARY_CLEAN) 00887 for (uint jj = 0; jj < itsW.size(); ++jj) 00888 out = WeightFilter::convolveHmax(out, itsW[jj]); 00889 else 00890 for (uint jj = 0; jj < itsW.size(); ++jj) 00891 out = WeightFilter::optConvolve(out, itsW[jj]); 00892 00893 return out; 00894 } 00895 00896 // ###################################################################### 00897 // WeightsMask implementation 00898 // ######################################################################} 00899 WeightsMask::WeightsMask() : WeightsDerived<WeightsMask>() 00900 { 00901 } 00902 00903 // ###################################################################### 00904 void WeightsMask::addWeight(const Image<double>& w) 00905 { 00906 itsW.push_back(w); 00907 itsInit = true; 00908 } 00909 00910 // ###################################################################### 00911 void WeightsMask::clear() 00912 { 00913 itsW.clear(); 00914 itsInit = false; 00915 } 00916 00917 // ######################################################################} 00918 Image<double> WeightsMask::compute(const Image<double>& in) 00919 { 00920 ASSERT((itsW.size() == in.size()) && in.size() > 0); 00921 00922 Image<double> out(in.getDims(), ZEROS); 00923 std::vector<Image<double> >::const_iterator iter(itsW.begin()), end(itsW.end()); 00924 Image<double>::iterator outiter(out.beginw()); 00925 00926 while (iter != end) 00927 { 00928 ASSERT(iter->size() == in.size()); 00929 (*outiter++) = sum(in * (*iter++)); 00930 } 00931 00932 return Image<double>(in.getDims(),ZEROS); 00933 } 00934 00935 // ###################################################################### 00936 // helper implementation 00937 // ###################################################################### 00938 Image<double> filterBinomial(const Image<double>& in, const uint iter, 00939 const uint taps, const BorderPolicy bp) 00940 { 00941 Image<double> out = in; 00942 if (bp == NONE) 00943 switch(taps) 00944 { 00945 case 3: 00946 for (uint i = 0; i < iter; ++i) 00947 out = lowPass3(out); 00948 break; 00949 case 5: 00950 for (uint i = 0; i < iter; ++i) 00951 out = lowPass5(out); 00952 break; 00953 default: 00954 { 00955 Image<double> k = binomialKernel(taps); 00956 for (uint i = 0; i < iter; ++i) 00957 out = WeightFilter::sepFilter(out, k, k, CONV_BOUNDARY_CLEAN); 00958 } 00959 } 00960 else 00961 for (uint i = 0; i < iter; ++i) 00962 out = lowPassLpt(out, taps, bp); 00963 00964 return out; 00965 } 00966 00967 // ###################################################################### 00968 template <class W> 00969 void printImpulse(const uint w, const uint h, W& weights) 00970 { 00971 Image<double> in(w,h,ZEROS); 00972 int cx = in.getWidth() / 2 -1; 00973 int cy = in.getHeight() / 2 -1; 00974 in.setVal(cx,cy,1.0); 00975 in = weights.compute(in); 00976 printImage(in); 00977 } 00978 00979 // ###################################################################### 00980 void printImage(const Image<double>& in) 00981 { 00982 int cx = in.getWidth() / 2 - 1; 00983 00984 Image<double>::const_iterator iter(in.begin() + cx); 00985 for (int i = 0; i < in.getHeight(); ++i) 00986 { 00987 LINFO("%3.5f", *iter); 00988 iter += in.getWidth(); 00989 } 00990 } 00991 00992 template 00993 void printImpulse(const uint w, const uint h, WeightsUniform& weights); 00994 template 00995 void printImpulse(const uint w, const uint h, WeightsBinomial& weights); 00996 template 00997 void printImpulse(const uint w, const uint h, WeightsCS& weights); 00998 template 00999 void printImpulse(const uint w, const uint h, WeightsDoG& weights); 01000 template 01001 void printImpulse(const uint w, const uint h, Weights1D& weights); 01002 template 01003 void printImpulse(const uint w, const uint h, Weights2D& weights); 01004 template 01005 void printImpulse(const uint w, const uint h, WeightsMask& weights); 01006 // ###################################################################### 01007 /* So things look consistent in everyone's emacs... */ 01008 /* Local Variables: */ 01009 /* indent-tabs-mode: nil */ 01010 /* End: */