00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #ifndef V1_H
00011 #define V1_H
00012
00013
00014 #include "Util/Types.H"
00015 #include "Util/log.H"
00016 #include "Image/ColorOps.H"
00017 #include "Image/Image.H"
00018 #include "Image/MathOps.H"
00019 #include "Image/DrawOps.H"
00020 #include "Image/FilterOps.H"
00021 #include "Image/Transforms.H"
00022 #include "Raster/Raster.H"
00023 #include "rutz/shared_ptr.h"
00024
00025 #include <vector>
00026
00027 #define TRACE_CONTOUR_DEPTH_LIMIT 3
00028 #define loThresh 10
00029 #define hiThresh 16
00030 #define sigma 2
00031
00032
00033
00034 class V1 {
00035 public:
00036 V1(Dims d);
00037 void processInput(Image<byte> i);
00038 bool traceContour(const Image<float> &magnitudeImage, const int x, const int y, const int from, const int steps);
00039 void nonMaxSuppressAndContTrace(Image<byte> &edgeImage, const Image<float> magnitudeImage, const Image<float> orientationImage);
00040 void cannyEdgeDetect(const Image<byte> source, Image<byte> &edgeImage, Image<float> &orientationImage);
00041 private:
00042 vector< Image<float> > layers;
00043 Image<byte> edgeImage;
00044 Dims itsDims;
00045
00046
00047
00048
00049 };
00050
00051 V1::V1(Dims d) {
00052 itsDims = d;
00053
00054 layers.resize(THETA_LEVELS, Image<float>(d, ZEROS));
00055 }
00056
00057 void V1::processInput(Image<byte> i) {
00058
00059 }
00060
00061
00062
00063 bool V1::traceContour(const Image<float> &magnitudeImage, const int x, const int y, const int from, const int steps) {
00064 if(magnitudeImage.getVal(x,y) >= hiThresh)
00065 return true;
00066 if(magnitudeImage.getVal(x,y) < loThresh)
00067 return false;
00068 if(x == 0 || x >= magnitudeImage.getWidth() - 1 || y == 0 || y >= magnitudeImage.getHeight() - 1)
00069 return false;
00070
00071 if(steps >= TRACE_CONTOUR_DEPTH_LIMIT)
00072 return false;
00073
00074 if(magnitudeImage.getVal(x-1,y) > loThresh && from != 1)
00075 if(traceContour(magnitudeImage, x-1, y, 5, steps+1))
00076 return true;
00077 if(magnitudeImage.getVal(x-1,y-1) > loThresh && from != 2)
00078 if(traceContour(magnitudeImage, x-1, y-1, 6, steps+1))
00079 return true;
00080 if(magnitudeImage.getVal(x-1,y+1) > loThresh && from != 8)
00081 if(traceContour(magnitudeImage, x-1, y+1, 4, steps+1))
00082 return true;
00083 if(magnitudeImage.getVal(x,y-1) > loThresh && from != 3)
00084 if(traceContour(magnitudeImage, x, y-1, 7, steps+1))
00085 return true;
00086 if(magnitudeImage.getVal(x,y+1) > loThresh && from != 7)
00087 if(traceContour(magnitudeImage, x, y+1, 3, steps+1))
00088 return true;
00089 if(magnitudeImage.getVal(x+1,y-1) > loThresh && from != 4)
00090 if(traceContour(magnitudeImage, x+1, y-1, 8, steps+1))
00091 return true;
00092 if(magnitudeImage.getVal(x+1,y) > loThresh && from != 5)
00093 if(traceContour(magnitudeImage, x+1, y, 1, steps+1))
00094 return true;
00095 if(magnitudeImage.getVal(x+1,y+1) > loThresh && from != 6)
00096 if(traceContour(magnitudeImage, x+1, y+1, 2, steps+1))
00097 return true;
00098
00099 return false;
00100 }
00101
00102 void V1::nonMaxSuppressAndContTrace(Image<byte> &edgeImage, const Image<float> magnitudeImage, const Image<float> orientationImage) {
00103 float mag, pa=0, pb=0, orientDeg;
00104
00105 for(int x = 1; x < magnitudeImage.getWidth() - 1; x++)
00106 for(int y = 1; y < magnitudeImage.getHeight() - 1; y++) {
00107 mag = magnitudeImage.getVal(x,y);
00108 orientDeg = orientationImage.getVal(x,y)*(180/PI);
00109
00110 if((orientDeg >= 0 && orientDeg <= 45) || (orientDeg > -180 && orientDeg <= -135)) {
00111 pa = (magnitudeImage.getVal(x+1,y) + magnitudeImage.getVal(x+1,y-1))/2;
00112 pb = (magnitudeImage.getVal(x-1,y) + magnitudeImage.getVal(x-1,y+1))/2;
00113 }
00114 else if((orientDeg > 45 && orientDeg <= 90) || (orientDeg > -135 && orientDeg <= -90)) {
00115 pa = (magnitudeImage.getVal(x+1,y-1) + magnitudeImage.getVal(x,y-1))/2;
00116 pb = (magnitudeImage.getVal(x-1,y+1) + magnitudeImage.getVal(x,y+1))/2;
00117 }
00118 else if((orientDeg > 90 && orientDeg <= 135) || (orientDeg > -90 && orientDeg <= -45)) {
00119 pa = (magnitudeImage.getVal(x,y-1) + magnitudeImage.getVal(x-1,y-1))/2;
00120 pb = (magnitudeImage.getVal(x,y+1) + magnitudeImage.getVal(x+1,y+1))/2;
00121 }
00122 else if((orientDeg > 135 && orientDeg <= 180) || (orientDeg > -45 && orientDeg < 0)) {
00123 pa = (magnitudeImage.getVal(x-1,y-1) + magnitudeImage.getVal(x-1,y))/2;
00124 pb = (magnitudeImage.getVal(x+1,y+1) + magnitudeImage.getVal(x+1,y))/2;
00125 }
00126
00127 if(mag > pa && mag > pb) {
00128 if(mag < loThresh)
00129 continue;
00130 else if(mag > hiThresh)
00131 edgeImage.setVal(x,y,255);
00132 else if(traceContour(magnitudeImage,x,y, -1, 0)) {
00133 edgeImage.setVal(x,y,255);
00134 }
00135 }
00136 }
00137 }
00138
00139 void V1::cannyEdgeDetect(const Image<byte> source, Image<byte> &edgeImage, Image<float> &orientationImage) {
00140
00141
00142 Image<float> magnitudeImage(source.getDims(), ZEROS);
00143
00144
00145
00146 Image<float> fblurImage = luminance(convGauss(source, sigma, sigma,10));
00147
00148
00149 gradient(fblurImage, magnitudeImage, orientationImage);
00150
00151
00152 nonMaxSuppressAndContTrace(edgeImage, magnitudeImage, orientationImage);
00153
00154 }
00155
00156
00157 #endif