00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038 #ifndef IMAGE_CONVOLUTIONS_C_DEFINED
00039 #define IMAGE_CONVOLUTIONS_C_DEFINED
00040
00041 #include "Image/Convolutions.H"
00042
00043 #include "Image/Image.H"
00044 #include "Image/Pixels.H"
00045 #include "rutz/trace.h"
00046
00047
00048 template <class T> static
00049 Image<typename promote_trait<T, float>::TP>
00050 convolveZeroHelper(const Image<T>& src, const float* filter,
00051 const int Nx, const int Ny)
00052 {
00053 GVX_TRACE(__PRETTY_FUNCTION__);
00054 ASSERT(src.initialized());
00055 const int w = src.getWidth(), h = src.getHeight();
00056
00057
00058
00059
00060
00061 typedef typename promote_trait<T, float>::TP TF;
00062 const Image<TF> source = src;
00063 Image<TF> result(w, h, NO_INIT);
00064 typename Image<TF>::const_iterator sptr = source.begin();
00065 typename Image<TF>::iterator dptr = result.beginw();
00066
00067 const int kkk = Nx * Ny - 1;
00068 const int Nx2 = (Nx - 1) / 2;
00069 const int Ny2 = (Ny - 1) / 2;
00070
00071
00072
00073 for (int j = 0; j < h; ++j)
00074 {
00075 const int j_offset = j-Ny2;
00076
00077 for (int i = 0; i < w; ++i)
00078 {
00079 TF sum = TF();
00080 const int i_offset = i-Nx2;
00081 const int kj_bgn = std::max(- j_offset, 0);
00082 const int kj_end = std::min(h - j_offset, Ny);
00083
00084 for (int kj = kj_bgn; kj < kj_end; ++kj)
00085 {
00086 const int kjj = kj + j_offset;
00087 const int src_offset = w * kjj + i_offset;
00088 const int filt_offset = kkk - Nx*kj;
00089
00090 const int ki_bgn = std::max(-i_offset, 0);
00091 const int ki_end = std::min(w-i_offset, Nx);
00092
00093 for (int ki = ki_bgn; ki < ki_end; ++ki)
00094 sum += sptr[ki + src_offset] * filter[filt_offset - ki];
00095 }
00096 *dptr++ = sum;
00097 }
00098 }
00099 return result;
00100 }
00101
00102
00103 template <class T> static
00104 Image<typename promote_trait<T, float>::TP>
00105 convolveCleanHelper(const Image<T>& src, const float* filter,
00106 const int Nx, const int Ny)
00107 {
00108 GVX_TRACE(__PRETTY_FUNCTION__);
00109 ASSERT(src.initialized());
00110 const int w = src.getWidth(), h = src.getHeight();
00111
00112
00113
00114
00115
00116 typedef typename promote_trait<T, float>::TP TF;
00117 const Image<TF> source = src;
00118 Image<TF> result(w, h, NO_INIT);
00119 typename Image<TF>::const_iterator sptr = source.begin();
00120 typename Image<TF>::iterator dptr = result.beginw();
00121
00122 const int kkk = Nx * Ny - 1;
00123 const int Nx2 = (Nx - 1) / 2;
00124 const int Ny2 = (Ny - 1) / 2;
00125
00126 float sumf = 0.0f;
00127 for (int i = 0; i < Nx*Ny; ++i)
00128 sumf += filter[i];
00129
00130
00131
00132 for (int j = 0; j < h; ++j)
00133 {
00134 const int j_offset = j-Ny2;
00135
00136 for (int i = 0; i < w; ++i)
00137 {
00138 TF sum = TF();
00139 float sumw = 0.0f;
00140 const int i_offset = i-Nx2;
00141 const int kj_bgn = std::max(- j_offset, 0);
00142 const int kj_end = std::min(h - j_offset, Ny);
00143
00144 for (int kj = kj_bgn; kj < kj_end; ++kj)
00145 {
00146 const int kjj = kj + j_offset;
00147 const int src_offset = w * kjj + i_offset;
00148 const int filt_offset = kkk - Nx*kj;
00149
00150 const int ki_bgn = std::max(-i_offset, 0);
00151 const int ki_end = std::min(w-i_offset, Nx);
00152
00153 for (int ki = ki_bgn; ki < ki_end; ++ki)
00154 {
00155 sum += sptr[ki + src_offset] * filter[filt_offset - ki];
00156 sumw += filter[filt_offset - ki];
00157 }
00158 }
00159 *dptr++ = sum * sumf / sumw;
00160 }
00161 }
00162 return result;
00163 }
00164
00165
00166 template <class T> static
00167 Image<typename promote_trait<T, float>::TP>
00168 convolve(const Image<T>& src, const float* filter,
00169 const int Nx, const int Ny,
00170 ConvolutionBoundaryStrategy boundary)
00171 {
00172 switch (boundary)
00173 {
00174 case CONV_BOUNDARY_ZERO:
00175 return convolveZeroHelper(src, filter, Nx, Ny);
00176 case CONV_BOUNDARY_CLEAN:
00177 return convolveCleanHelper(src, filter, Nx, Ny);
00178 case CONV_BOUNDARY_REPLICATE:
00179
00180 break;
00181 }
00182
00183 LFATAL("convolution boundary strategy %d not supported",
00184 (int) boundary);
00185 return Image<typename promote_trait<T, float>::TP>();
00186 }
00187
00188
00189 template <class T>
00190 Image<typename promote_trait<T, float>::TP>
00191 optConvolve(const Image<T>& src, const Image<float>& f)
00192 {
00193 GVX_TRACE(__PRETTY_FUNCTION__);
00194 ASSERT(src.initialized());
00195
00196 const int src_w = src.getWidth();
00197 const int src_h = src.getHeight();
00198
00199 Image<float>::const_iterator filter = f.begin();
00200 const int fil_w = f.getWidth();
00201 const int fil_h = f.getHeight();
00202
00203 ASSERT((fil_w & 1) && (fil_h & 1));
00204
00205 typedef typename promote_trait<T, float>::TP TF;
00206 const Image<TF> source = src;
00207 Image<TF> result(src_w, src_h, NO_INIT);
00208 typename Image<TF>::const_iterator sptr = source.begin();
00209 typename Image<TF>::iterator dptr = result.beginw();
00210
00211 const int fil_end = fil_w * fil_h - 1;
00212 const int Nx2 = (fil_w - 1) / 2;
00213 const int Ny2 = (fil_h - 1) / 2;
00214
00215 const int srow_skip = src_w-fil_w;
00216
00217 for (int dst_y = 0; dst_y < src_h; ++dst_y)
00218 {
00219
00220 const bool y_clean = dst_y >= Ny2 && dst_y < (src_h - Nx2);
00221
00222 for (int dst_x = 0; dst_x < src_w; ++dst_x, ++dptr)
00223 {
00224
00225 const bool x_clean = dst_x >= Nx2 && dst_x < (src_w - Nx2);
00226
00227
00228
00229
00230
00231
00232 if (x_clean && y_clean)
00233 {
00234 float dst_val = 0.0f;
00235
00236 Image<float>::const_iterator fptr = filter+fil_end;
00237
00238 Image<float>::const_iterator srow_ptr =
00239 sptr + src_w*(dst_y-Nx2) + dst_x - Nx2;
00240
00241 for (int f_y = 0; f_y < fil_h; ++f_y)
00242 {
00243 for (int f_x = 0; f_x < fil_w; ++f_x)
00244 dst_val += (*srow_ptr++) * (*fptr--);
00245
00246 srow_ptr += srow_skip;
00247 }
00248 *dptr = dst_val;
00249 continue;
00250 }
00251 else
00252 {
00253
00254
00255
00256
00257
00258
00259
00260 float dst_val = 0.0f;
00261 float src_sum = 0.0f;
00262 int src_cnt = 0;
00263 float fil_sum_skipped = 0.0f;
00264
00265 for (int f_y = 0; f_y < fil_h; ++f_y)
00266 {
00267 const int src_y = f_y + dst_y - Ny2;
00268 if (src_y >= 0 && src_y < src_h)
00269 {
00270 for (int f_x = 0; f_x < fil_w; ++f_x)
00271 {
00272 const float fil = filter[fil_end - f_x - fil_w*f_y];
00273
00274 const int src_x = f_x + dst_x - Nx2;
00275 if (src_x >= 0 && src_x < src_w)
00276 {
00277 const float src_val = sptr[src_x + src_w * src_y];
00278 dst_val += src_val * fil;
00279 src_sum += src_val;
00280 ++src_cnt;
00281 }
00282 else
00283 {
00284 fil_sum_skipped += fil;
00285 }
00286 }
00287 }
00288 else
00289 {
00290 for (int f_x = 0; f_x < fil_w; ++f_x)
00291 fil_sum_skipped += filter[fil_end - f_x - fil_w*f_y];
00292 }
00293 }
00294 const float src_avg = src_sum / src_cnt;
00295 *dptr = dst_val + (fil_sum_skipped * src_avg);
00296 }
00297 }
00298 }
00299 return result;
00300 }
00301
00302
00303 template <class T>
00304 Image<typename promote_trait<T, float>::TP>
00305 convolveHmax(const Image<T>& src, const Image<float>& filter)
00306 {
00307 GVX_TRACE(__PRETTY_FUNCTION__);
00308 ASSERT(src.initialized());
00309 const int Nx = filter.getWidth(), Ny = filter.getHeight();
00310 ASSERT((Nx & 1) && (Ny & 1));
00311
00312 const int w = src.getWidth(), h = src.getHeight();
00313
00314
00315
00316
00317
00318 typedef typename promote_trait<T, float>::TP TF;
00319 const Image<TF> source = src;
00320 Image<TF> result(w, h, NO_INIT);
00321 typename Image<TF>::const_iterator sptr = source.begin();
00322 typename Image<TF>::iterator dptr = result.beginw();
00323 typename Image<float>::const_iterator const filt = filter.begin();
00324
00325 int kkk = Nx * Ny - 1;
00326 int Nx2 = (Nx - 1) / 2, Ny2 = (Ny - 1) / 2;
00327
00328
00329 for (int j = 0; j < h; ++j)
00330 for (int i = 0; i < w; ++i)
00331 {
00332 TF sum = TF(), sumw = TF();
00333 for (int kj = 0; kj < Ny; ++kj)
00334 {
00335 int kjj = kj + j - Ny2;
00336 if (kjj >= 0 && kjj < h)
00337 for (int ki = 0; ki < Nx; ++ki)
00338 {
00339 int kii = ki + i - Nx2;
00340 if (kii >= 0 && kii < w)
00341 {
00342 float fil = filt[kkk - ki - Nx*kj];
00343 TF img = sptr[kii + w * kjj];
00344 sum += img * fil; sumw += img * img;
00345 }
00346 }
00347 }
00348
00349 if (sumw > 0.0F) sum = fabs(sum)/sqrt(sumw);
00350 *dptr++ = sum;
00351 }
00352 return result;
00353 }
00354
00355
00356 template <class T>
00357 static Image<typename promote_trait<T, float>::TP>
00358 xFilter(const Image<T>& src, const float* hFilt, const int hfs,
00359 ConvolutionBoundaryStrategy boundary)
00360 {
00361 GVX_TRACE(__PRETTY_FUNCTION__);
00362 const int w = src.getWidth(), h = src.getHeight();
00363
00364
00365
00366
00367
00368 typedef typename promote_trait<T, float>::TP TF;
00369 const Image<TF> source = src;
00370 if (hfs == 0) return source;
00371 Image<TF> result(w, h, NO_INIT);
00372 typename Image<TF>::const_iterator sptr = source.begin();
00373 typename Image<TF>::iterator dptr = result.beginw();
00374
00375 const int hfs2 = (hfs - 1) / 2;
00376
00377
00378 float *hFilter = new float[hfs]; float sumh = 0.0f;
00379 for (int x = 0; x < hfs; x ++)
00380 { sumh += hFilt[x]; hFilter[hfs-1-x] = hFilt[x]; }
00381
00382
00383 if (w < hfs)
00384 {
00385 switch (boundary)
00386 {
00387 case CONV_BOUNDARY_ZERO:
00388 {
00389 for (int j = 0; j < h; j ++)
00390 for (int i = 0; i < w; i ++)
00391 {
00392 TF val = TF();
00393 for (int k = 0; k < hfs; k ++)
00394 if (i + k - hfs2 >= 0 && i + k - hfs2 < w)
00395 {
00396 val += sptr[k - hfs2] * hFilter[k];
00397 }
00398 *dptr++ = val; sptr ++;
00399 }
00400 }
00401 break;
00402 case CONV_BOUNDARY_CLEAN:
00403 {
00404 for (int j = 0; j < h; j ++)
00405 for (int i = 0; i < w; i ++)
00406 {
00407 TF val = TF(); float sum = 0.0F;
00408 for (int k = 0; k < hfs; k ++)
00409 if (i + k - hfs2 >= 0 && i + k - hfs2 < w)
00410 {
00411 val += sptr[k - hfs2] * hFilter[k];
00412 sum += hFilter[k];
00413 }
00414 *dptr++ = val * sumh / sum; sptr ++;
00415 }
00416 }
00417 break;
00418 case CONV_BOUNDARY_REPLICATE:
00419 {
00420 for (int j = 0; j < h; j ++)
00421 for (int i = 0; i < w; i ++)
00422 {
00423 TF val = TF();
00424 for (int k = 0; k < hfs; k ++)
00425 if (i + k - hfs2 < 0)
00426 {
00427 val += sptr[-i] * hFilter[k];
00428 }
00429 else if (i + k - hfs2 >= w)
00430 {
00431 val += sptr[w-1-i] * hFilter[k];
00432 }
00433 else
00434 {
00435 val += sptr[k - hfs2] * hFilter[k];
00436 }
00437 *dptr++ = val; sptr ++;
00438 }
00439 }
00440 break;
00441 default:
00442 LFATAL("invalid convolution boundary strategy %d",
00443 (int) boundary);
00444 }
00445 }
00446 else
00447 for (int jj = 0; jj < h; jj ++)
00448 {
00449
00450 switch (boundary)
00451 {
00452 case CONV_BOUNDARY_ZERO:
00453 {
00454 for (int j = hfs2; j > 0; --j)
00455 {
00456 TF val = TF();
00457 for (int k = j; k < hfs; ++k)
00458 {
00459 val += sptr[k - j] * hFilter[k];
00460 }
00461 *dptr++ = val;
00462 }
00463 }
00464 break;
00465 case CONV_BOUNDARY_CLEAN:
00466 {
00467 for (int j = hfs2; j > 0; --j)
00468 {
00469 TF val = TF(); float sum = 0.0F;
00470 for (int k = j; k < hfs; ++k)
00471 {
00472 val += sptr[k - j] * hFilter[k];
00473 sum += hFilter[k];
00474 }
00475 *dptr++ = val * sumh / sum;
00476 }
00477 }
00478 break;
00479 case CONV_BOUNDARY_REPLICATE:
00480 {
00481 for (int j = hfs2; j > 0; --j)
00482 {
00483 TF val = TF();
00484 for (int k = 0; k < j; ++k)
00485 {
00486 val += sptr[0] * hFilter[k];
00487 }
00488 for (int k = j; k < hfs; ++k)
00489 {
00490 val += sptr[k - j] * hFilter[k];
00491 }
00492 *dptr++ = val;
00493 }
00494 }
00495 break;
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512
00513 default:
00514 LFATAL("invalid convolution boundary strategy %d",
00515 (int) boundary);
00516 }
00517
00518 for (int i = 0; i < w - hfs + 1; i ++)
00519 {
00520 TF val = TF();
00521 for (int k = 0; k < hfs; k ++) val += sptr[k] * hFilter[k];
00522 *dptr++ = val; sptr++;
00523 }
00524
00525 switch (boundary)
00526 {
00527 case CONV_BOUNDARY_ZERO:
00528 {
00529 for (int j = hfs - 1; j > hfs2; --j)
00530 {
00531 TF val = TF();
00532 for (int k = 0; k < j; ++k)
00533 {
00534 val += sptr[k] * hFilter[k];
00535 }
00536 *dptr++ = val;
00537 sptr++;
00538 }
00539 }
00540 break;
00541 case CONV_BOUNDARY_CLEAN:
00542 {
00543 for (int j = hfs - 1; j > hfs2; --j)
00544 {
00545 TF val = TF(); float sum = 0.0F;
00546 for (int k = 0; k < j; ++k)
00547 {
00548 val += sptr[k] * hFilter[k];
00549 sum += hFilter[k];
00550 }
00551 *dptr++ = val * sumh / sum;
00552 sptr++;
00553 }
00554 }
00555 break;
00556 case CONV_BOUNDARY_REPLICATE:
00557 {
00558 for (int j = hfs - 1; j > hfs2; --j)
00559 {
00560 TF val = TF();
00561 for (int k = 0; k < j; ++k)
00562 {
00563 val += sptr[k] * hFilter[k];
00564 }
00565 for (int k = j; k < hfs; ++k)
00566 {
00567 val += sptr[j-1] * hFilter[k];
00568 }
00569 *dptr++ = val;
00570 sptr++;
00571 }
00572 }
00573 break;
00574
00575
00576
00577
00578
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588
00589
00590
00591
00592 default:
00593 LFATAL("invalid convolution boundary strategy %d",
00594 (int) boundary);
00595 }
00596 sptr += hfs2;
00597 }
00598 delete [] hFilter;
00599 return result;
00600 }
00601
00602
00603 template <class T>
00604 static Image<typename promote_trait<T, float>::TP>
00605 yFilter(const Image<T>& src, const float* vFilt, const int vfs,
00606 ConvolutionBoundaryStrategy boundary)
00607 {
00608 GVX_TRACE(__PRETTY_FUNCTION__);
00609 const int w = src.getWidth(), h = src.getHeight();
00610
00611
00612
00613
00614
00615 typedef typename promote_trait<T, float>::TP TF;
00616 const Image<TF> source = src;
00617 if (vfs == 0) return source;
00618 Image<TF> result(w, h, NO_INIT);
00619 typename Image<TF>::const_iterator sptr = source.begin();
00620 typename Image<TF>::iterator dptr = result.beginw();
00621
00622 const int vfs2 = (vfs - 1) / 2;
00623
00624
00625 float *vFilter = new float[vfs]; float sumv = 0.0f;
00626 for (int x = 0; x < vfs; x ++)
00627 { sumv += vFilt[x]; vFilter[vfs-1-x] = vFilt[x]; }
00628
00629 int ww[vfs];
00630 for (int i = 0; i < vfs; i ++) ww[i] = w * i;
00631
00632 if (h < vfs)
00633 {
00634 switch (boundary)
00635 {
00636 case CONV_BOUNDARY_ZERO:
00637 {
00638 for (int j = 0; j < h; j ++)
00639 for (int i = 0; i < w; i ++)
00640 {
00641 TF val = TF();
00642 for (int k = 0; k < vfs; k ++)
00643 if (j + k - vfs2 >= 0 && j + k - vfs2 < h)
00644 {
00645 val += sptr[w * (k - vfs2)] * vFilter[k];
00646 }
00647 *dptr++ = val; sptr ++;
00648 }
00649 }
00650 break;
00651 case CONV_BOUNDARY_CLEAN:
00652 {
00653 for (int j = 0; j < h; j ++)
00654 for (int i = 0; i < w; i ++)
00655 {
00656 TF val = TF(); float sum = 0.0;
00657 for (int k = 0; k < vfs; k ++)
00658 if (j + k - vfs2 >= 0 && j + k - vfs2 < h)
00659 {
00660 val += sptr[w * (k - vfs2)] * vFilter[k];
00661 sum += vFilter[k];
00662 }
00663 *dptr++ = val * sumv / sum; sptr ++;
00664 }
00665 }
00666 break;
00667 case CONV_BOUNDARY_REPLICATE:
00668 {
00669 for (int j = 0; j < h; j ++)
00670 for (int i = 0; i < w; i ++)
00671 {
00672 TF val = TF();
00673 for (int k = 0; k < vfs; k ++)
00674 if (j + k - vfs2 < 0)
00675 {
00676 val += sptr[w * (-j)] * vFilter[k];
00677 }
00678 else if (j + k - vfs2 >= h)
00679 {
00680 val += sptr[w * (h-1-j)] * vFilter[k];
00681 }
00682 else
00683 {
00684 val += sptr[w * (k - vfs2)] * vFilter[k];
00685 }
00686 *dptr++ = val; sptr ++;
00687 }
00688 }
00689 break;
00690 default:
00691 LFATAL("invalid convolution boundary strategy %d",
00692 (int) boundary);
00693 }
00694 }
00695 else
00696 {
00697
00698 switch (boundary)
00699 {
00700 case CONV_BOUNDARY_ZERO:
00701 {
00702 for (int j = vfs2; j > 0; --j)
00703 {
00704 for (int i = 0; i < w; ++i)
00705 {
00706 TF val = TF();
00707 for (int k = j; k < vfs; ++k)
00708 {
00709 val += sptr[ww[k - j]] * vFilter[k];
00710 }
00711 *dptr++ = val;
00712 sptr++;
00713 }
00714 sptr -= w;
00715 }
00716 }
00717 break;
00718 case CONV_BOUNDARY_CLEAN:
00719 {
00720 for (int j = vfs2; j > 0; --j)
00721 {
00722 for (int i = 0; i < w; ++i)
00723 {
00724 TF val = TF(); float sum = 0.0;
00725 for (int k = j; k < vfs; ++k)
00726 {
00727 val += sptr[ww[k - j]] * vFilter[k];
00728 sum += vFilter[k];
00729 }
00730 *dptr++ = val * sumv / sum;
00731 sptr++;
00732 }
00733 sptr -= w;
00734 }
00735 }
00736 break;
00737 case CONV_BOUNDARY_REPLICATE:
00738 {
00739 for (int j = vfs2; j > 0; --j)
00740 {
00741 for (int i = 0; i < w; ++i)
00742 {
00743 TF val = TF();
00744 for (int k = 0; k < j; ++k)
00745 {
00746 val += sptr[ww[0]] * vFilter[k];
00747 }
00748 for (int k = j; k < vfs; ++k)
00749 {
00750 val += sptr[ww[k - j]] * vFilter[k];
00751 }
00752 *dptr++ = val;
00753 sptr++;
00754 }
00755 sptr -= w;
00756 }
00757 }
00758 break;
00759 default:
00760 LFATAL("invalid convolution boundary strategy %d",
00761 (int) boundary);
00762 }
00763
00764 for (int j = 0; j < h - vfs + 1; j ++)
00765 for (int i = 0; i < w; i ++)
00766 {
00767 TF val = TF();
00768 for (int k = 0; k < vfs; k ++) val += sptr[ww[k]] * vFilter[k];
00769 *dptr++ = val; sptr ++;
00770 }
00771
00772 switch (boundary)
00773 {
00774 case CONV_BOUNDARY_ZERO:
00775 {
00776 for (int j = vfs - 1; j > vfs2; --j)
00777 for (int i = 0; i < w; ++i)
00778 {
00779 TF val = TF();
00780 for (int k = 0; k < j; ++k)
00781 {
00782 val += sptr[ww[k]] * vFilter[k];
00783 }
00784 *dptr++ = val;
00785 sptr ++;
00786 }
00787 }
00788 break;
00789 case CONV_BOUNDARY_CLEAN:
00790 {
00791 for (int j = vfs - 1; j > vfs2; --j)
00792 for (int i = 0; i < w; ++i)
00793 {
00794 TF val = TF(); float sum = 0.0;
00795 for (int k = 0; k < j; ++k)
00796 {
00797 val += sptr[ww[k]] * vFilter[k];
00798 sum += vFilter[k];
00799 }
00800 *dptr++ = val * sumv / sum;
00801 sptr ++;
00802 }
00803 }
00804 break;
00805 case CONV_BOUNDARY_REPLICATE:
00806 {
00807 for (int j = vfs - 1; j > vfs2; --j)
00808 for (int i = 0; i < w; ++i)
00809 {
00810 TF val = TF();
00811 for (int k = 0; k < j; ++k)
00812 {
00813 val += sptr[ww[k]] * vFilter[k];
00814 }
00815 for (int k = j; k < vfs; ++k)
00816 {
00817 val += sptr[ww[j-1]] * vFilter[k];
00818 }
00819 *dptr++ = val;
00820 sptr ++;
00821 }
00822 }
00823 break;
00824 default:
00825 LFATAL("invalid convolution boundary strategy %d",
00826 (int) boundary);
00827 }
00828 }
00829 delete [] vFilter;
00830 return result;
00831 }
00832
00833
00834 template <class T>
00835 Image<typename promote_trait<T, float>::TP>
00836 sepFilter(const Image<T>& src, const Image<float>& hFilter,
00837 const Image<float>& vFilter,
00838 ConvolutionBoundaryStrategy boundary)
00839 {
00840 ASSERT(hFilter.is1D() || hFilter.getSize() == 0);
00841 ASSERT(vFilter.is1D() || vFilter.getSize() == 0);
00842 return sepFilter(src, hFilter.getArrayPtr(), vFilter.getArrayPtr(),
00843 hFilter.getSize(), vFilter.getSize(), boundary);
00844 }
00845
00846
00847 template <class T>
00848 Image<typename promote_trait<T, float>::TP>
00849 sepFilter(const Image<T>& src, const float* hFilt, const float* vFilt,
00850 const int hfs, const int vfs,
00851 ConvolutionBoundaryStrategy boundary)
00852 {
00853 Image<typename promote_trait<T, float>::TP> result = src;
00854
00855 if (hfs > 0) result = xFilter(result, hFilt, hfs, boundary);
00856 if (vfs > 0) result = yFilter(result, vFilt, vfs, boundary);
00857
00858 return result;
00859 }
00860
00861
00862 #include "inst/Image/Convolutions.I"
00863
00864
00865
00866
00867
00868
00869
00870
00871 #endif // IMAGE_CONVOLUTIONS_C_DEFINED