CudaPyramidOps.C

00001 #include "CUDA/CudaImage.H"
00002 #include "CUDA/CudaImageSet.H"
00003 #include "Util/log.H"
00004 #include "Image/PyramidOps.H"
00005 #include "CudaPyramidOps.H"
00006 #include "CUDA/CudaLowPass.H"
00007 #include "CUDA/CudaKernels.H"
00008 #include "CUDA/CudaMathOps.H"
00009 #include "CUDA/CudaShapeOps.H"
00010 #include "CUDA/CudaFilterOps.H"
00011 
00012 // ######################################################################
00013 // ##### Pyramid builder functions:
00014 // ######################################################################
00015 
00016 // ######################################################################
00017 CudaImageSet<float> cudaBuildPyrGaussian(const CudaImage<float>& image,
00018                              int firstlevel, int depth, int filterSize)
00019 {
00020   ASSERT(image.initialized());
00021 
00022   CudaImageSet<float> result(depth);
00023 
00024   if (0 >= firstlevel)
00025     result[0] = image;
00026 
00027   CudaImage<float> a = CudaImage<float>(image);
00028   for (int lev = 1; lev < depth; ++lev)
00029     {
00030       switch(filterSize)
00031         {
00032         case 5:
00033           a = cudaLowPass5yDec(cudaLowPass5xDec(a));
00034           break;
00035         default:
00036           a = cudaDecX(cudaLowPassX(filterSize, a));
00037           a = cudaDecY(cudaLowPassY(filterSize, a));
00038           break;
00039         }
00040 
00041       // NOTE: when lev < firstlevel, we leave result[lev] empty even
00042       // though it isn't any extra work to fill it in; that way, other
00043       // functions that see the result ImageSet might be able to gain
00044       // additional speed-ups by seeing that some of the images are
00045       // empty and avoid processing them further
00046       if (lev >= firstlevel)
00047         result[lev] = a;
00048     }
00049 
00050   return result;
00051 }
00052 
00053 
00054 
00055 // ######################################################################
00056 CudaImageSet<float> cudaBuildPyrLaplacian(const CudaImage<float>& image, int firstlevel, int depth, int filterSize)
00057 {
00058   ASSERT(image.initialized());
00059 
00060   CudaImageSet<float> result(depth);
00061 
00062   CudaImage<float> lpf = cudaLowPass(filterSize, image);
00063 
00064   if (0 >= firstlevel)
00065    result[0] = cudaSubtractImages(image,lpf);
00066   for (int lev = 1; lev < depth; ++lev)
00067     {
00068       const CudaImage<float> dec = cudaDecXY(lpf);
00069       lpf = cudaLowPass(filterSize, dec);
00070 
00071       if (lev >= firstlevel)
00072         result[lev] = cudaSubtractImages(dec,lpf);
00073 
00074     }
00075 
00076   return result;
00077 }
00078 
00079 
00080 // ######################################################################
00081 CudaImageSet<float> cudaBuildPyrOrientedFromLaplacian(const CudaImageSet<float>& laplacian,
00082                                           int filterSize,
00083                                           float theta, float intens)
00084 {
00085   int attenuation_width = -1;
00086   float spatial_freq = -1.0;
00087 
00088   switch (filterSize)
00089     {
00090     case 5: attenuation_width = 3; spatial_freq = M_PI_2; break;
00091     case 9: attenuation_width = 5; spatial_freq = 2.6; break;
00092     default:
00093       LFATAL("Filter size %d is not supported", filterSize);
00094     }
00095 
00096   // compute oriented filter from laplacian:
00097   CudaImageSet<float> result(laplacian.size());
00098 
00099   for (size_t lev = 0; lev < result.size(); ++lev)
00100     {
00101       if (laplacian[lev].initialized())
00102         {
00103           result[lev] = cudaOrientedFilter(laplacian[lev], spatial_freq,
00104                                        theta, intens);
00105           // attenuate borders that are overestimated due to filter trunctation:
00106           cudaInplaceAttenuateBorders(result[lev], attenuation_width);
00107         }
00108     }
00109 
00110   return result;
00111 }
00112 
00113 // ######################################################################
00114 CudaImageSet<float> cudaBuildPyrOriented(const CudaImage<float>& image, int firstlevel, int depth, int filterSize,
00115                              float theta, float intens)
00116 {
00117   ASSERT(image.initialized());
00118 
00119   const CudaImageSet<float> laplacian = cudaBuildPyrLaplacian(image, firstlevel, depth, filterSize);
00120 
00121   const CudaImageSet<float> orifilt =
00122     cudaBuildPyrOrientedFromLaplacian(laplacian, filterSize, theta,
00123                                   intens);
00124 
00125   CudaImageSet<float> result(orifilt.size());
00126   for (size_t i = 0; i < result.size(); ++i)
00127     result[i] = orifilt[i];
00128 
00129   return result;
00130 }
00131 
00132 
00133 
00134 // ######################################################################
00135 CudaImageSet<float> cudaBuildPyrLocalAvg(const CudaImage<float>& image, int depth)
00136 {
00137   ASSERT(image.initialized());
00138   ASSERT(depth >= 1);
00139 
00140   CudaImageSet<float> result(depth);
00141 
00142   // only deepest level of pyr is filled with local avg:
00143   const int scale = int(pow(2.0, depth - 1));
00144   result[depth - 1] = cudaQuickLocalAvg(image, scale);
00145 
00146   return result;
00147 }
00148 
00149 // ######################################################################
00150 CudaImageSet<float> cudaBuildPyrLocalAvg2x2(const CudaImage<float>& image, int depth)
00151 {
00152   ASSERT(depth >= 0);
00153 
00154   if (depth == 0)
00155     return CudaImageSet<float>(0);
00156 
00157   CudaImageSet<float> result(depth);
00158   result[0] = image;
00159 
00160   for (int i = 1; i < depth; ++i)
00161     result[i] = cudaQuickLocalAvg2x2(result[i-1]);
00162 
00163   return result;
00164 }
00165 
00166 // ######################################################################
00167 CudaImageSet<float> cudaBuildPyrLocalMax(const CudaImage<float>& image, int depth)
00168 {
00169   ASSERT(image.initialized());
00170   ASSERT(depth >= 1);
00171 
00172   CudaImageSet<float> result(depth);
00173 
00174   // only deepest level of pyr is filled with local max:
00175   const int scale = int(pow(2.0, depth - 1));
00176   result[depth - 1] = cudaQuickLocalMax(image, scale);
00177 
00178   return result;
00179 }
00180 
00181 
00182 CudaImageSet<float> cudaBuildPyrGeneric(const CudaImage<float>& image,
00183                             int firstlevel, int depth,
00184                             const PyramidType typ, const float gabor_theta,
00185                             const float intens)
00186 {
00187   switch(typ)
00188     {
00189     case Gaussian3: return cudaBuildPyrGaussian(image, firstlevel, depth, 3);
00190     case Gaussian5: return cudaBuildPyrGaussian(image, firstlevel, depth, 5);
00191     case Gaussian9: return cudaBuildPyrGaussian(image, firstlevel, depth, 9);
00192 
00193     case Laplacian5: return cudaBuildPyrLaplacian(image, firstlevel, depth, 5);
00194     case Laplacian9: return cudaBuildPyrLaplacian(image, firstlevel, depth, 9);
00195 
00196     case Oriented5: return cudaBuildPyrOriented(image, firstlevel, depth, 5, gabor_theta, intens);
00197     case Oriented9: return cudaBuildPyrOriented(image, firstlevel, depth, 9, gabor_theta, intens);
00198 
00199     case QuickLocalAvg: return cudaBuildPyrLocalAvg(image, depth);
00200     case QuickLocalMax: return cudaBuildPyrLocalMax(image, depth);
00201 
00202     default:
00203       LFATAL("Attempt to create Pyramid of unknown type %d", typ);
00204     }
00205 
00206   ASSERT(false);
00207   return CudaImageSet<float>(0); // "can't happen", but placate compiler
00208 }
00209 
00210 
00211 
00212 // ######################################################################
00213 // CudaImageSet<float> cudaBuildPyrGabor(const CudaImageSet<float>& gaussianPyr,
00214 //                               float angle, float filter_period,
00215 //                                       float elongation, int size, int flags, MemoryPolicy mp, int dev)
00216 // {
00217 //   const double major_stddev = filter_period / 3.0;
00218 //   const double minor_stddev = major_stddev * elongation;
00219 
00220 //   // We have to add 90 to the angle here when constructing the gabor
00221 //   // filter. That's because the angle used to build the gabor filter
00222 //   // actually specifies the direction along which the grating
00223 //   // varies. This direction is orthogonal to the the direction of the
00224 //   // contours that the grating will detect.
00225 //   const double theta = angle + 90.0f;
00226 
00227 //   // In concept, we want to filter with four phases of the filter: odd
00228 //   // on+off, and even on+off (that would be xox, oxo, xo, and ox). But
00229 //   // since the on version just produces the negation of the off version,
00230 //   // we can get the summed output of both by just taking the absolute
00231 //   // value of the outputs of one of them. So we only need to convolve
00232 //   // with the filter in two phases, then take the absolute value (i.e.,
00233 //   // we're doing |xox| and |xo|).
00234 
00235 //   CudaImage<float> g0 = cudaGaborFilter3(major_stddev, minor_stddev,
00236 //                                          filter_period, 0.0f, theta, size, mp, dev);
00237 //   CudaImage<float> g90 = cudaGaborFilter3(major_stddev, minor_stddev,
00238 //                                           filter_period, 90.0f, theta, size, mp, dev);
00239 //   LDEBUG("angle = %.2f, period = %.2f pix, size = %dx%d pix",
00240 //          angle, filter_period, g0.getWidth(), g0.getHeight());
00241 
00242 //   CudaImage<float> f0, f90;
00243 //   CudaImageSet<float> result(gaussianPyr.size());
00244 
00245 //   for (uint i = 0; i < gaussianPyr.size(); ++i)
00246 //     {
00247 //       // if the i'th level in our input is empty, then leave it empty
00248 //       // in the output as well:
00249 //       if (!gaussianPyr[i].initialized())
00250 //         continue;
00251 //       if (flags & DO_ENERGY_NORM)
00252 //         {
00253 //           CudaImage<float> temp = cudaEnergyNorm(in);
00254 //           f0 = cudaOptConvolve(temp, g0);
00255 //           f90 = cudaOptConvolve(temp, g90);
00256 //         }
00257 //       else
00258 //         {
00259 //           f0 = cudaOptConvolve(in, g0);
00260 //           f90 = cudaOptConvolve(in, g90);
00261 //         }
00262 
00263 //       if (!(flags & NO_ABS))
00264 //         {
00265 //           f0 = cudaAbs(f0);
00266 //           f90 = cudaAbs(f90);
00267 //         }
00268 //       result[i] = f0;
00269 //       result[i] += f90;
00270 //     }
00271 //   return result;
00272 // }
00273 
00274 
00275 CudaImage<float> cudaCenterSurround(const CudaImageSet<float>& pyr,
00276                         const int lev1, const int lev2,
00277                         const bool absol,
00278                         const CudaImageSet<float>* clipPyr)
00279 {
00280   ASSERT(lev1 >= 0 && lev2 >= 0);
00281   ASSERT(uint(lev1) < pyr.size() && uint(lev2) < pyr.size());
00282 
00283   const int largeLev = std::min(lev1, lev2);
00284   const int smallLev = std::max(lev1, lev2);
00285 
00286   if (clipPyr != 0 && clipPyr->isNonEmpty())
00287     {
00288       ASSERT((*clipPyr)[largeLev].getDims() == pyr[largeLev].getDims());
00289       ASSERT((*clipPyr)[smallLev].getDims() == pyr[smallLev].getDims());
00290 
00291       return
00292         ::cudaCenterSurround(pyr[largeLev]*(*clipPyr)[largeLev],
00293                              pyr[smallLev]*(*clipPyr)[smallLev],
00294                              absol);
00295     }
00296   else
00297     return ::cudaCenterSurround(pyr[largeLev], pyr[smallLev], absol);
00298 }
00299 
00300 void cudaCenterSurround(const CudaImageSet<float>& pyr,
00301                     const int lev1, const int lev2,
00302                     CudaImage<float>& pos, CudaImage<float>& neg,
00303                     const CudaImageSet<float>* clipPyr)
00304 {
00305   ASSERT(lev1 >= 0 && lev2 >= 0);
00306   ASSERT(uint(lev1) < pyr.size() && uint(lev2) < pyr.size());
00307 
00308   const int largeLev = std::min(lev1, lev2);
00309   const int smallLev = std::max(lev1, lev2);
00310 
00311   if (clipPyr != 0 && clipPyr->isNonEmpty())
00312     {
00313       ASSERT((*clipPyr)[largeLev].getDims() == pyr[largeLev].getDims());
00314       ASSERT((*clipPyr)[smallLev].getDims() == pyr[smallLev].getDims());
00315 
00316       ::cudaCenterSurround(pyr[largeLev]*(*clipPyr)[largeLev],
00317                            pyr[smallLev]*(*clipPyr)[smallLev],
00318                            pos, neg);
00319     }
00320   else
00321     ::cudaCenterSurround(pyr[largeLev], pyr[smallLev], pos, neg);
00322 }
00323 
00324 CudaImage<float> cudaCenterSurroundSingleOpponent(const CudaImageSet<float>& cpyr,
00325                                       const CudaImageSet<float>& spyr,
00326                                       const int lev1, const int lev2,
00327                                       const bool absol,
00328                                       const CudaImageSet<float>* clipPyr)
00329 {
00330   ASSERT(lev1 >= 0 && lev2 >= 0);
00331   ASSERT(uint(lev1) < cpyr.size() && uint(lev2) < cpyr.size());
00332   ASSERT(uint(lev1) < spyr.size() && uint(lev2) < spyr.size());
00333 
00334   const int largeLev = std::min(lev1, lev2);
00335   const int smallLev = std::max(lev1, lev2);
00336 
00337   if (clipPyr != 0 && clipPyr->isNonEmpty())
00338     {
00339       ASSERT((*clipPyr)[largeLev].getDims() == cpyr[largeLev].getDims());
00340       ASSERT((*clipPyr)[smallLev].getDims() == cpyr[smallLev].getDims());
00341       ASSERT((*clipPyr)[largeLev].getDims() == spyr[largeLev].getDims());
00342       ASSERT((*clipPyr)[smallLev].getDims() == spyr[smallLev].getDims());
00343 
00344       return
00345         ::cudaCenterSurround(cpyr[largeLev]*(*clipPyr)[largeLev],
00346                              spyr[smallLev]*(*clipPyr)[smallLev],
00347                              absol);
00348     }
00349   else
00350     return ::cudaCenterSurround(cpyr[largeLev], spyr[smallLev], absol);
00351 }
00352 
00353 void cudaCenterSurroundSingleOpponent(const CudaImageSet<float>& cpyr,
00354                                   const CudaImageSet<float>& spyr,
00355                                   const int lev1, const int lev2,
00356                                   CudaImage<float>& pos, CudaImage<float>& neg,
00357                                   const CudaImageSet<float>* clipPyr)
00358 {
00359   ASSERT(lev1 >= 0 && lev2 >= 0);
00360   ASSERT(uint(lev1) < cpyr.size() && uint(lev2) < cpyr.size());
00361   ASSERT(uint(lev1) < spyr.size() && uint(lev2) < spyr.size());
00362 
00363   const int largeLev = std::min(lev1, lev2);
00364   const int smallLev = std::max(lev1, lev2);
00365 
00366   if (clipPyr != 0 && clipPyr->isNonEmpty())
00367     {
00368       ASSERT((*clipPyr)[largeLev].getDims() == cpyr[largeLev].getDims());
00369       ASSERT((*clipPyr)[smallLev].getDims() == cpyr[smallLev].getDims());
00370       ASSERT((*clipPyr)[largeLev].getDims() == spyr[largeLev].getDims());
00371       ASSERT((*clipPyr)[smallLev].getDims() == spyr[smallLev].getDims());
00372 
00373       ::cudaCenterSurround(cpyr[largeLev]*(*clipPyr)[largeLev],
00374                        spyr[smallLev]*(*clipPyr)[smallLev],
00375                        pos, neg);
00376     }
00377   else
00378     ::cudaCenterSurround(cpyr[largeLev], spyr[smallLev], pos, neg);
00379 }
00380 
00381 CudaImage<float> cudaCenterSurroundDiff(const CudaImageSet<float>& pyr1,
00382                             const CudaImageSet<float>& pyr2,
00383                             const int lev1, const int lev2,
00384                             const bool absol,
00385                             const CudaImageSet<float>* clipPyr)
00386 {
00387   ASSERT(lev1 >= 0 && lev2 >= 0);
00388   ASSERT(uint(lev1) < pyr1.size() && uint(lev2) < pyr1.size());
00389 
00390   const int largeLev = std::min(lev1, lev2);
00391   const int smallLev = std::max(lev1, lev2);
00392 
00393   ASSERT(pyr1[largeLev].getDims() == pyr2[largeLev].getDims());
00394   ASSERT(pyr1[smallLev].getDims() == pyr2[smallLev].getDims());
00395 
00396   // compute differences between the two pyramids:
00397   const CudaImage<float> limg = pyr1[largeLev]-pyr2[largeLev];
00398   const CudaImage<float> simg = pyr1[smallLev]-pyr2[smallLev];
00399 
00400   if (clipPyr != 0 && clipPyr->isNonEmpty())
00401     {
00402       ASSERT((*clipPyr)[largeLev].getDims() == limg.getDims());
00403       ASSERT((*clipPyr)[smallLev].getDims() == simg.getDims());
00404 
00405       return ::cudaCenterSurround(limg*(*clipPyr)[largeLev],
00406                                   simg*(*clipPyr)[smallLev],
00407                                   absol);
00408     }
00409   else
00410     return ::cudaCenterSurround(limg, simg, absol);
00411 }
00412 
00413 void cudaCenterSurroundDiff(const CudaImageSet<float>& pyr1,
00414                         const CudaImageSet<float>& pyr2,
00415                         const int lev1, const int lev2,
00416                         CudaImage<float>& pos, CudaImage<float>& neg,
00417                         const CudaImageSet<float>* clipPyr)
00418 {
00419   ASSERT(lev1 >= 0 && lev2 >= 0);
00420   ASSERT(uint(lev1) < pyr1.size() && uint(lev2) < pyr1.size());
00421 
00422   const int largeLev = std::min(lev1, lev2);
00423   const int smallLev = std::max(lev1, lev2);
00424 
00425   ASSERT(pyr1[largeLev].getDims() == pyr2[largeLev].getDims());
00426   ASSERT(pyr1[smallLev].getDims() == pyr2[smallLev].getDims());
00427 
00428   // compute differences between the two pyramids:
00429   const CudaImage<float> limg = pyr1[largeLev]-pyr2[largeLev];
00430   const CudaImage<float> simg = pyr1[smallLev]-pyr2[smallLev];
00431 
00432   if (clipPyr != 0 && clipPyr->isNonEmpty())
00433     {
00434       ASSERT((*clipPyr)[largeLev].getDims() == limg.getDims());
00435       ASSERT((*clipPyr)[smallLev].getDims() == simg.getDims());
00436 
00437       ::cudaCenterSurround(limg*(*clipPyr)[largeLev],
00438                        simg*(*clipPyr)[smallLev],
00439                        pos, neg);
00440     }
00441   else
00442     ::cudaCenterSurround(limg, simg, pos, neg);
00443 }
00444 
00445 
00446 CudaImage<float> cudaCenterSurroundDiffSingleOpponent(const CudaImageSet<float>& cpyr1,
00447                                           const CudaImageSet<float>& cpyr2,
00448                                           const CudaImageSet<float>& spyr1,
00449                                           const CudaImageSet<float>& spyr2,
00450                                           const int lev1, const int lev2,
00451                                           const bool absol,
00452                                           const CudaImageSet<float>* clipPyr)
00453 {
00454   ASSERT(lev1 >= 0 && lev2 >= 0);
00455   ASSERT(uint(lev1) < cpyr1.size() && uint(lev2) < cpyr1.size());
00456 
00457   const int largeLev = std::min(lev1, lev2);
00458   const int smallLev = std::max(lev1, lev2);
00459 
00460   ASSERT(cpyr1[largeLev].getDims() == cpyr2[largeLev].getDims());
00461   ASSERT(cpyr1[smallLev].getDims() == cpyr2[smallLev].getDims());
00462   ASSERT(spyr1[largeLev].getDims() == spyr2[largeLev].getDims());
00463   ASSERT(spyr1[smallLev].getDims() == spyr2[smallLev].getDims());
00464 
00465   // compute differences between the two pyramids:
00466   const CudaImage<float> limg = cpyr1[largeLev]-cpyr2[largeLev];
00467   const CudaImage<float> simg = spyr1[smallLev]-spyr2[smallLev];
00468 
00469   if (clipPyr != 0 && clipPyr->isNonEmpty())
00470     {
00471       ASSERT((*clipPyr)[largeLev].getDims() == limg.getDims());
00472       ASSERT((*clipPyr)[smallLev].getDims() == simg.getDims());
00473 
00474       return ::cudaCenterSurround(limg*(*clipPyr)[largeLev],
00475                                   simg*(*clipPyr)[smallLev],
00476                                   absol);
00477     }
00478   else
00479     return ::cudaCenterSurround(limg, simg, absol);
00480 }
00481 
00482 
00483 void cudaCenterSurroundDiffSingleOpponent(const CudaImageSet<float>& cpyr1,
00484                                       const CudaImageSet<float>& cpyr2,
00485                                       const CudaImageSet<float>& spyr1,
00486                                       const CudaImageSet<float>& spyr2,
00487                                       const int lev1, const int lev2,
00488                                       CudaImage<float>& pos, CudaImage<float>& neg,
00489                                       const CudaImageSet<float>* clipPyr)
00490 {
00491   ASSERT(lev1 >= 0 && lev2 >= 0);
00492   ASSERT(uint(lev1) < cpyr1.size() && uint(lev2) < cpyr1.size());
00493 
00494   const int largeLev = std::min(lev1, lev2);
00495   const int smallLev = std::max(lev1, lev2);
00496 
00497   ASSERT(cpyr1[largeLev].getDims() == cpyr2[largeLev].getDims());
00498   ASSERT(cpyr1[smallLev].getDims() == cpyr2[smallLev].getDims());
00499   ASSERT(spyr1[largeLev].getDims() == spyr2[largeLev].getDims());
00500   ASSERT(spyr1[smallLev].getDims() == spyr2[smallLev].getDims());
00501 
00502   // compute differences between the two pyramids:
00503   const CudaImage<float> limg = cpyr1[largeLev]-cpyr2[largeLev];
00504   const CudaImage<float> simg = spyr1[smallLev]-spyr2[smallLev];
00505 
00506   if (clipPyr != 0 && clipPyr->isNonEmpty())
00507     {
00508       ASSERT((*clipPyr)[largeLev].getDims() == limg.getDims());
00509       ASSERT((*clipPyr)[smallLev].getDims() == simg.getDims());
00510 
00511       ::cudaCenterSurround(limg*(*clipPyr)[largeLev],
00512                            simg*(*clipPyr)[smallLev],
00513                            pos, neg);
00514     }
00515   else
00516     ::cudaCenterSurround(limg, simg, pos, neg);
00517 }
Generated on Sun May 8 08:04:44 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3