getEuclideanDistance.h

Go to the documentation of this file.
00001 
00015 #ifndef _DLRCOMPUTERVISION_EUCLIDEANDISTANCE_H_
00016 #define _DLRCOMPUTERVISION_EUCLIDEANDISTANCE_H_
00017 
00018 #include <list>
00019 #include <dlrComputerVision/imageFormat.h>
00020 #include <dlrComputerVision/imageIO.h>
00021 #include <dlrComputerVision/image.h>
00022 
00023 namespace dlr {
00024 
00025   namespace computerVision {
00026     
00027     template<ImageFormat FORMAT>
00028     Array2D<double>
00029     getEuclideanDistance(const Image<FORMAT>& inputImage,
00030                          size_t maxNumberOfPasses=10);
00031 
00032 
00033     template<ImageFormat FORMAT>
00034     Array2D<double>
00035     getEuclideanDistance(const Image<FORMAT>& inputImage,
00036                          size_t maxNumberOfPasses,
00037                          size_t& numberOfPassesUsed);
00038   
00039   } // namespace computerVision
00040 
00041 } // namespace dlr
00042 
00043 
00044 /* ============ Definitions of inline & template functions ============ */
00045 
00046 
00047 #include <cmath>
00048 #include <dlrNumeric/index2D.h>
00049 
00050 namespace dlr {
00051 
00052   namespace computerVision {
00053     
00055     namespace privateCode {
00056 
00057       inline bool
00058       eucDistPropagate(size_t toIndex,
00059                        size_t fromIndex,
00060                        Array2D<double>& distanceMap,
00061                        Array2D<Index2D>& referentMap,
00062                        int row,
00063                        int column)
00064       {
00065         // Inexpensive check to see if we _might_ need to update.
00066         if(distanceMap(fromIndex) < distanceMap(toIndex)) {
00067           Index2D& referent = referentMap(fromIndex);
00068           double deltaU = column - referent.getColumn();
00069           double deltaV = row - referent.getRow();
00070           double newDistance = deltaU * deltaU + deltaV * deltaV;
00071           if(newDistance < distanceMap(toIndex)) {
00072             distanceMap(toIndex) = newDistance;
00073             referentMap(toIndex) = referent;
00074             return true;
00075           }
00076         }
00077         return false;
00078       }
00079 
00080     } // namespace privateCode
00082 
00083   
00084     template<ImageFormat FORMAT>
00085     Array2D<double>
00086     getEuclideanDistance(const Image<FORMAT>& inputImage,
00087                          size_t maxNumberOfPasses)
00088     {
00089       size_t numberOfPassesUsed;
00090       return getEuclideanDistance(inputImage, maxNumberOfPasses,
00091                                   numberOfPassesUsed);
00092     }
00093 
00094 
00095     template<ImageFormat FORMAT>
00096     Array2D<double>
00097     getEuclideanDistance(const Image<FORMAT>& inputImage,
00098                          size_t maxNumberOfPasses,
00099                          size_t& numberOfPassesUsed)
00100     {
00101       Array2D<double> distanceMap(inputImage.rows(), inputImage.columns());
00102       Array2D<Index2D> referentMap(inputImage.rows(), inputImage.columns());
00103 
00104       // Initialize the distance matrix.
00105       double maxSqDistance = (inputImage.rows() * inputImage.rows()
00106                               + inputImage.columns() * inputImage.columns());
00107       size_t index0 = 0;
00108       for(size_t row = 0; row < inputImage.rows(); ++row) {
00109         for(size_t column = 0; column < inputImage.columns(); ++column) {
00110           if(inputImage(index0)) {
00111             distanceMap(index0) = 0.0;
00112             referentMap(index0) = Index2D(static_cast<int>(row), static_cast<int>(column));
00113           } else {
00114             distanceMap(index0) = maxSqDistance;
00115           }
00116           ++index0;
00117         }
00118       }
00119 
00120       // This is hard to do efficiently closed-form, so we'll iterate.
00121       // If numberOfPasses is set to 1, we'll still get a reasonable
00122       // map.
00123       size_t columns = distanceMap.columns();
00124       size_t rows = distanceMap.rows();
00125       size_t passNumber;
00126       for(passNumber = 0; passNumber < maxNumberOfPasses; ++passNumber) {
00127         // This variable will tell us if we can quit early because the
00128         // distances are all correct.
00129         bool isChanged = false;
00130       
00131         // === Propagate distances East. === 
00132 
00133         // Propagate distances East along top row.
00134         index0 = 1;
00135         for(size_t column = 1; column < inputImage.columns(); ++column) {
00136           isChanged |= privateCode::eucDistPropagate(
00137             index0, index0 - 1, distanceMap, referentMap,
00138             0, static_cast<int>(column));
00139           isChanged |= privateCode::eucDistPropagate(
00140             index0, index0 + columns - 1, distanceMap, referentMap,
00141             0, static_cast<int>(column));
00142           ++index0;
00143         }
00144 
00145         // Propagate distances East through the bulk of the image.
00146         for(size_t row = 1; row < inputImage.rows() - 1; ++row) {
00147           index0 = row * inputImage.columns() + 1;
00148           for(size_t column = 1; column < inputImage.columns(); ++column) {
00149             isChanged |= privateCode::eucDistPropagate(
00150               index0, index0 - columns - 1, distanceMap, referentMap,
00151               static_cast<int>(row), static_cast<int>(column));
00152             isChanged |= privateCode::eucDistPropagate(
00153               index0, index0 - 1, distanceMap, referentMap,
00154               static_cast<int>(row), static_cast<int>(column));
00155             isChanged |= privateCode::eucDistPropagate(
00156               index0, index0 + columns - 1, distanceMap, referentMap,
00157               static_cast<int>(row), static_cast<int>(column));
00158             ++index0;
00159           }
00160         }
00161 
00162         // Propagate distances East along bottom row.
00163         index0 = (inputImage.rows() - 1) * inputImage.columns() + 1;
00164         for(size_t column = 1; column < inputImage.columns(); ++column) {
00165           isChanged |= privateCode::eucDistPropagate(
00166             index0, index0 - columns - 1, distanceMap, referentMap,
00167             static_cast<int>(rows) - 1, static_cast<int>(column));
00168           isChanged |= privateCode::eucDistPropagate(
00169             index0, index0 - 1, distanceMap, referentMap,
00170             static_cast<int>(rows) - 1, static_cast<int>(column));
00171           ++index0;
00172         }
00173 
00174         // === Propagate distances South. ===
00175         index0 = columns + 1;
00176         for(size_t row = 1; row < inputImage.rows(); ++row) {
00177           index0 = row * inputImage.columns();
00178 
00179           // Update first pixel of the row.
00180           isChanged |= privateCode::eucDistPropagate(
00181             index0, index0 - columns, distanceMap, referentMap,
00182             static_cast<int>(row), 0);
00183           isChanged |= privateCode::eucDistPropagate(
00184             index0, index0 - columns + 1, distanceMap, referentMap,
00185             static_cast<int>(row), 0);
00186           ++index0;
00187 
00188           // Update the bulk of the pixels in the current row.
00189           for(size_t column = 1; column < inputImage.columns() - 1; ++column) {
00190             isChanged |= privateCode::eucDistPropagate(
00191               index0, index0 - columns - 1, distanceMap, referentMap,
00192               static_cast<int>(row), static_cast<int>(column));
00193             isChanged |= privateCode::eucDistPropagate(
00194               index0, index0 - columns, distanceMap, referentMap,
00195               static_cast<int>(row), static_cast<int>(column));
00196             isChanged |= privateCode::eucDistPropagate(
00197               index0, index0 - columns + 1, distanceMap, referentMap,
00198               static_cast<int>(row), static_cast<int>(column));
00199             ++index0;
00200           }
00201 
00202           // Update last pixel of the row.
00203           isChanged |= privateCode::eucDistPropagate(
00204             index0, index0 - columns - 1, distanceMap, referentMap,
00205             static_cast<int>(row), static_cast<int>(columns) - 1);
00206           isChanged |= privateCode::eucDistPropagate(
00207             index0, index0 - columns, distanceMap, referentMap,
00208             static_cast<int>(row), static_cast<int>(columns) - 1);
00209           ++index0;
00210         }
00211 
00212         // === Propagate distances West. ===
00213 
00214         // Propagate distances West along top row.
00215         index0 = columns - 2;
00216 
00217         // Trick here... note that column wraps around to a very large
00218         // number once instead of going negative.
00219         for(size_t column = inputImage.columns() - 2; column < columns;
00220             --column) {
00221           isChanged |= privateCode::eucDistPropagate(
00222             index0, index0 + 1, distanceMap, referentMap,
00223             0, static_cast<int>(column));
00224           isChanged |= privateCode::eucDistPropagate(
00225             index0, index0 + columns + 1, distanceMap, referentMap,
00226             0, static_cast<int>(column));
00227           --index0;
00228         }
00229       
00230         // Propagate distances West through the bulk of the image.
00231         for(size_t row = 1; row < inputImage.rows() - 1; ++row) {
00232           index0 = (row + 1) * inputImage.columns() - 2;
00233           for(size_t column = inputImage.columns() - 2; column < columns;
00234               --column) {
00235             isChanged |= privateCode::eucDistPropagate(
00236               index0, index0 - columns + 1, distanceMap, referentMap,
00237               static_cast<int>(row), static_cast<int>(column));
00238             isChanged |= privateCode::eucDistPropagate(
00239               index0, index0 + 1, distanceMap, referentMap,
00240               static_cast<int>(row), static_cast<int>(column));
00241             isChanged |= privateCode::eucDistPropagate(
00242               index0, index0 + columns + 1, distanceMap, referentMap,
00243               static_cast<int>(row), static_cast<int>(column));
00244             --index0;
00245           }
00246         }
00247       
00248         // Propagate distances West along bottom row.
00249         index0 = rows * columns - 2;
00250         for(size_t column = inputImage.columns() - 2; column < columns; --column) {
00251           isChanged |= privateCode::eucDistPropagate(
00252             index0, index0 - columns + 1, distanceMap, referentMap,
00253             static_cast<int>(rows - 1), static_cast<int>(column));
00254           isChanged |= privateCode::eucDistPropagate(
00255             index0, index0 + 1, distanceMap, referentMap,
00256             static_cast<int>(rows - 1), static_cast<int>(column));
00257           --index0;
00258         }
00259 
00260 
00261         // === Propagate distances North. ===
00262 
00263         // Remember that row wraps around to a very large number instead
00264         // of going negative.
00265         for(size_t row = inputImage.rows() - 2; row < rows; --row) {
00266           index0 = row * columns;
00267 
00268           // Update first pixel of the row.
00269           isChanged |= privateCode::eucDistPropagate(
00270             index0, index0 + columns, distanceMap, referentMap,
00271             static_cast<int>(row), 0);
00272           isChanged |= privateCode::eucDistPropagate(
00273             index0, index0 + columns + 1, distanceMap, referentMap,
00274             static_cast<int>(row), 0);
00275           ++index0;
00276 
00277           // Update the bulk of the pixels in the current row.
00278           for(size_t column = 1; column < inputImage.columns() - 1; ++column) {
00279             isChanged |= privateCode::eucDistPropagate(
00280               index0, index0 + columns - 1, distanceMap, referentMap,
00281               static_cast<int>(row), static_cast<int>(column));
00282             isChanged |= privateCode::eucDistPropagate(
00283               index0, index0 + columns, distanceMap, referentMap,
00284               static_cast<int>(row), static_cast<int>(column));
00285             isChanged |= privateCode::eucDistPropagate(
00286               index0, index0 + columns + 1, distanceMap, referentMap,
00287               static_cast<int>(row), static_cast<int>(column));
00288             ++index0;
00289           }
00290 
00291           // Update last pixel of the row.
00292           isChanged |= privateCode::eucDistPropagate(
00293             index0, index0 + columns - 1, distanceMap, referentMap,
00294             static_cast<int>(row), static_cast<int>(columns) - 1);
00295           isChanged |= privateCode::eucDistPropagate(
00296             index0, index0 + columns, distanceMap, referentMap,
00297             static_cast<int>(row), static_cast<int>(columns) - 1);
00298           ++index0;
00299         }
00300 
00301         // If no pixels needed changing, we're done.
00302         if(!isChanged) {
00303           break;
00304         }
00305       }
00306 
00307       // Convert squared distance to distance.
00308       for(index0 = 0; index0 < distanceMap.size(); ++index0) {
00309         distanceMap(index0) = std::sqrt(distanceMap(index0));
00310       }
00311 
00312       numberOfPassesUsed = passNumber;
00313       return distanceMap;
00314     }
00315   
00316   } // namespace computerVision
00317   
00318 } // namespace dlr
00319 
00320 #endif /* #ifndef _DLRCOMPUTERVISION_EUCLIDEANDISTANCE_H_ */
00321 
00322 
00323 
00324 
00325 
00326 

Generated on Wed Nov 25 12:15:05 2009 for dlrComputerVision Utility Library by  doxygen 1.5.8