00001
00015 #ifndef _DLRCOMPUTERVISION_CANNY_H_
00016 #define _DLRCOMPUTERVISION_CANNY_H_
00017
00018 #include <dlrComputerVision/image.h>
00019
00020 namespace dlr {
00021
00022 namespace computerVision {
00023
00024
00028 template <ImageFormat FORMAT>
00029 Image<GRAY1>
00030 applyCanny(const Image<FORMAT>& inputImage,
00031 size_t gaussianSize=5,
00032 double upperThreshold=0.0,
00033 double lowerThreshold=0.0);
00034
00035 }
00036
00037 }
00038
00039
00040
00041
00042 #include <list>
00043 #include <dlrComputerVision/filter.h>
00044 #include <dlrComputerVision/kernels.h>
00045 #include <dlrComputerVision/nonMaximumSuppress.h>
00046 #include <dlrComputerVision/sobel.h>
00047 #include <dlrComputerVision/utilities.h>
00048 #include <dlrNumeric/index2D.h>
00049 #include <dlrNumeric/utilities.h>
00050
00051 namespace dlr {
00052
00053 namespace computerVision {
00054
00056 namespace privateCode {
00057
00058 Image<GRAY1>
00059 traceEdges(const Image<GRAY_FLOAT64>& gradImage, double threshold)
00060 {
00061 Image<GRAY1> edgeImage(gradImage.rows(), gradImage.columns());
00062 edgeImage = false;
00063
00064 std::list<Index2D> seedList;
00065 size_t index0 = 0;
00066 for(size_t row = 0; row < gradImage.rows(); ++row) {
00067 for(size_t column = 0; column < gradImage.columns(); ++column) {
00068 if(gradImage[index0] > threshold) {
00069 edgeImage[index0] = true;
00070 seedList.push_front(Index2D(static_cast<int>(row), static_cast<int>(column)));
00071 }
00072 ++index0;
00073 }
00074 }
00075
00076 size_t lastRow = gradImage.rows() - 1;
00077 size_t lastColumn = gradImage.columns() - 1;
00078 size_t columns = gradImage.columns();
00079 while(seedList.size() != 0) {
00080 Index2D seed = *seedList.begin();
00081 seedList.pop_front();
00082 size_t row = seed.getRow();
00083 size_t column = seed.getColumn();
00084 if(row == 0 || column == 0
00085 || row == lastRow || column == lastColumn) {
00086 continue;
00087 }
00088 index0 = row * columns + column;
00089
00090 size_t neighborIndex = index0 - columns - 1;
00091 if(gradImage(neighborIndex) != 0.0
00092 && edgeImage(neighborIndex) == false) {
00093 edgeImage(neighborIndex) = true;
00094 seedList.push_front(Index2D(static_cast<int>(row) - 1, static_cast<int>(column) - 1));
00095 }
00096 neighborIndex = index0 - columns;
00097 if(gradImage(neighborIndex) != 0.0
00098 && edgeImage(neighborIndex) == false) {
00099 edgeImage(neighborIndex) = true;
00100 seedList.push_front(Index2D(static_cast<int>(row) - 1, static_cast<int>(column)));
00101 }
00102 neighborIndex = index0 - columns + 1;
00103 if(gradImage(neighborIndex) != 0.0
00104 && edgeImage(neighborIndex) == false) {
00105 edgeImage(neighborIndex) = true;
00106 seedList.push_front(Index2D(static_cast<int>(row) - 1, static_cast<int>(column) + 1));
00107 }
00108 neighborIndex = index0 - 1;
00109 if(gradImage(neighborIndex) != 0.0
00110 && edgeImage(neighborIndex) == false) {
00111 edgeImage(neighborIndex) = true;
00112 seedList.push_front(Index2D(static_cast<int>(row), static_cast<int>(column) - 1));
00113 }
00114 neighborIndex = index0 + 1;
00115 if(gradImage(neighborIndex) != 0.0
00116 && edgeImage(neighborIndex) == false) {
00117 edgeImage(neighborIndex) = true;
00118 seedList.push_front(Index2D(static_cast<int>(row), static_cast<int>(column) + 1));
00119 }
00120 neighborIndex = index0 + columns - 1;
00121 if(gradImage(neighborIndex) != 0.0
00122 && edgeImage(neighborIndex) == false) {
00123 edgeImage(neighborIndex) = true;
00124 seedList.push_front(Index2D(static_cast<int>(row) + 1, static_cast<int>(column) - 1));
00125 }
00126 neighborIndex = index0 + columns;
00127 if(gradImage(neighborIndex) != 0.0
00128 && edgeImage(neighborIndex) == false) {
00129 edgeImage(neighborIndex) = true;
00130 seedList.push_front(Index2D(static_cast<int>(row) + 1, static_cast<int>(column)));
00131 }
00132 neighborIndex = index0 + columns + 1;
00133 if(gradImage(neighborIndex) != 0.0
00134 && edgeImage(neighborIndex) == false) {
00135 edgeImage(neighborIndex) = true;
00136 seedList.push_front(Index2D(static_cast<int>(row) + 1, static_cast<int>(column) + 1));
00137 }
00138 }
00139 return edgeImage;
00140 }
00141
00142 }
00144
00145
00146
00147
00148 template <ImageFormat FORMAT>
00149 Image<GRAY1>
00150 applyCanny(const Image<FORMAT>& inputImage,
00151 size_t gaussianSize,
00152 double upperThreshold,
00153 double lowerThreshold)
00154 {
00155
00156 if(inputImage.rows() < gaussianSize + 3
00157 || inputImage.columns() < gaussianSize + 3) {
00158 DLR_THROW(ValueException, "applyCanny()",
00159 "Argument inputImage has insufficient size.");
00160 }
00161 if(lowerThreshold > upperThreshold) {
00162 DLR_THROW(ValueException, "applyCanny()",
00163 "Argument lowerThreshold must be less than or equal to "
00164 "Arguments upperThreshold.");
00165 }
00166
00167
00168
00169
00170
00171
00172
00173 lowerThreshold *= std::sqrt(2.0) * 8.0;
00174 upperThreshold *= std::sqrt(2.0) * 8.0;
00175
00176
00177 Image<GRAY_FLOAT64> blurredImage;
00178 if(gaussianSize == 0) {
00179 blurredImage = convertColorspace<GRAY_FLOAT64>(inputImage);
00180 } else {
00181 Kernel<double> gaussian =
00182 getGaussianKernel<double>(gaussianSize, gaussianSize);
00183 blurredImage = filter2D<GRAY_FLOAT64, GRAY_FLOAT64>(
00184 gaussian, inputImage, 0.0);
00185 }
00186
00187
00188
00189 Image<GRAY_FLOAT64> gradX = applySobelX(blurredImage);
00190 Image<GRAY_FLOAT64> gradY = applySobelY(blurredImage);
00191 Image<GRAY_FLOAT64> gradMagnitude(gradX.rows(), gradX.columns());
00192
00193 if(lowerThreshold > 0.0 && upperThreshold > 0.0) {
00194
00195 for(size_t index0 = 0; index0 < gradX.size(); ++index0) {
00196 double tmpVal = std::sqrt(
00197 gradX[index0] * gradX[index0] + gradY[index0] * gradY[index0]);
00198 gradMagnitude[index0] = (tmpVal > lowerThreshold) ? tmpVal : 0.0;
00199 }
00200 } else {
00201
00202 for(size_t index0 = 0; index0 < gradX.size(); ++index0) {
00203 gradMagnitude[index0] = std::sqrt(
00204 gradX[index0] * gradX[index0] + gradX[index0] * gradX[index0]);
00205 }
00206
00207
00208 if(upperThreshold <= 0.0) {
00209 Float64 maxGrad = maximum(gradMagnitude.ravel());
00210 Float64 minGrad = minimum(gradMagnitude.ravel());
00211 upperThreshold = minGrad + 0.9 * (maxGrad - minGrad);
00212 }
00213 if(lowerThreshold <= 0.0) {
00214 lowerThreshold = 0.9 * upperThreshold;
00215 }
00216 for(size_t index0 = 0; index0 < gradX.size(); ++index0) {
00217 double tmpVal = gradMagnitude[index0];
00218 gradMagnitude[index0] = (tmpVal > lowerThreshold) ? tmpVal : 0.0;
00219 }
00220 }
00221
00222
00223 Image<GRAY_FLOAT64> edgeCandidates =
00224 nonMaximumSuppress(gradMagnitude, gradX, gradY);
00225
00226
00227 Image<GRAY1> edgeImage =
00228 privateCode::traceEdges(edgeCandidates, upperThreshold);
00229 return edgeImage;
00230 }
00231
00232 }
00233
00234 }
00235
00236 #endif