degate  0.1.2
CannyEdgeDetection.cc
Go to the documentation of this file.
00001 /* -*-c++-*-
00002 
00003  This file is part of the IC reverse engineering tool degate.
00004 
00005  Copyright 2008, 2009, 2010 by Martin Schobert
00006 
00007  Degate is free software: you can redistribute it and/or modify
00008  it under the terms of the GNU General Public License as published by
00009  the Free Software Foundation, either version 3 of the License, or
00010  any later version.
00011 
00012  Degate is distributed in the hope that it will be useful,
00013  but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  GNU General Public License for more details.
00016 
00017  You should have received a copy of the GNU General Public License
00018  along with degate. If not, see <http://www.gnu.org/licenses/>.
00019 
00020 */
00021 
00022 #include <CannyEdgeDetection.h>
00023 #include <IPPipe.h>
00024 #include <IPCopy.h>
00025 #include <IPConvolve.h>
00026 #include <IPNormalize.h>
00027 #include <IPThresholding.h>
00028 #include <ImageManipulation.h>
00029 #include <IPImageWriter.h>
00030 
00031 using namespace degate;
00032 
00033 CannyEdgeDetection::CannyEdgeDetection(unsigned int min_x, unsigned int max_x,
00034                                        unsigned int min_y, unsigned int max_y,
00035                                        unsigned int wire_diameter,
00036                                        unsigned int median_filter_width,
00037                                        unsigned int blur_kernel_size,
00038                                        double sigma,
00039                                        double _hysteresis_min,
00040                                        double _hysteresis_max) :
00041   EdgeDetection(min_x, max_x, min_y, max_y, median_filter_width, blur_kernel_size, sigma),
00042   hysteresis_min(_hysteresis_min),
00043   hysteresis_max(_hysteresis_max) {
00044   }
00045 
00046 CannyEdgeDetection::~CannyEdgeDetection() {}
00047 
00048 
00049 TileImage_GS_DOUBLE_shptr CannyEdgeDetection::run(ImageBase_shptr img_in,
00050                                                   TileImage_GS_DOUBLE_shptr probability_map) {
00051   run_edge_detection(img_in);
00052   TileImage_GS_DOUBLE_shptr edge_image = get_edge_image(probability_map);
00053   TileImage_GS_DOUBLE_shptr edge_magnitude_image = get_edge_magnitude_image(probability_map);
00054 
00055   TileImage_GS_DOUBLE_shptr sup_edge_image(new TileImage_GS_DOUBLE(get_width(), get_height()));
00056   non_maximum_supression(get_horizontal_edges(), get_vertical_edges(),
00057                          edge_magnitude_image, sup_edge_image);
00058 
00059   normalize<TileImage_GS_DOUBLE, TileImage_GS_DOUBLE>(sup_edge_image, sup_edge_image, 0, 1);
00060 
00061   hysteresis(sup_edge_image);
00062 
00063   return sup_edge_image;
00064 }
00065 
00066 TileImage_GS_DOUBLE_shptr CannyEdgeDetection::run(ImageBase_shptr img_in,
00067                                                   TileImage_GS_DOUBLE_shptr probability_map,
00068                                                   std::string const& directory) {
00069 
00070   set_directory(directory);
00071   TileImage_GS_DOUBLE_shptr sup_edge_image = run(img_in, probability_map);
00072 
00073   save_normalized_image<TileImage_GS_DOUBLE>(join_pathes(directory, "06_hysteresis.tif"),
00074                                              sup_edge_image);
00075 
00076   return sup_edge_image;
00077 }
00078 
00079 
00080 void CannyEdgeDetection::hysteresis(TileImage_GS_DOUBLE_shptr sup_edge_image) {
00081   unsigned int x, y;
00082   for(y = get_border(); y < sup_edge_image->get_height() - get_border(); y++) {
00083     for(x = get_border(); x < sup_edge_image->get_width() - get_border(); x++) {
00084       if(sup_edge_image->get_pixel(x, y) >= hysteresis_max)
00085         sup_edge_image->set_pixel(x, y, 1);
00086       else if(sup_edge_image->get_pixel(x, y) <= hysteresis_min)
00087         sup_edge_image->set_pixel(x, y, 0);
00088       else
00089         sup_edge_image->set_pixel(x, y, 2);
00090     }
00091   }
00092 
00093 
00094   bool running = true;
00095   while(running) {
00096     running = false;
00097 
00098     for(y = get_border(); y < sup_edge_image->get_height() - get_border(); y++) {
00099       for(x = get_border(); x < sup_edge_image->get_width() - get_border(); x++) {
00100         if(sup_edge_image->get_pixel(x, y) == 2 &&
00101            ( sup_edge_image->get_pixel(x-1, y-1) == 1 ||
00102              sup_edge_image->get_pixel(x  , y-1) == 1 ||
00103              sup_edge_image->get_pixel(x+1, y-1) == 1 ||
00104 
00105              sup_edge_image->get_pixel(x-1, y) == 1 ||
00106              sup_edge_image->get_pixel(x+1, y) == 1 ||
00107 
00108              sup_edge_image->get_pixel(x-1, y+1) == 1 ||
00109              sup_edge_image->get_pixel(x  , y+1) == 1 ||
00110              sup_edge_image->get_pixel(x+1, y+1) == 1)) {
00111 
00112           sup_edge_image->set_pixel(x, y, 1);
00113           running = true;
00114         }
00115       }
00116     }
00117   }
00118 
00119 }
00120 
00121 
00122 void CannyEdgeDetection::non_maximum_supression(TileImage_GS_DOUBLE_shptr horizontal_edges,
00123                                                 TileImage_GS_DOUBLE_shptr vertical_edges,
00124                                                 TileImage_GS_DOUBLE_shptr edge_image,
00125                                                 TileImage_GS_DOUBLE_shptr sup_edge_image) {
00126 
00127   for(unsigned int y = get_border(); y < edge_image->get_height() - get_border(); y++) {
00128     for(unsigned int x = get_border(); x < edge_image->get_width() - get_border(); x++) {
00129 
00130       int gradient_direction = get_gradient_direction(horizontal_edges,
00131                                                       vertical_edges, edge_image, x, y);
00132 
00133       gs_double_pixel_t pix = edge_image->get_pixel(x, y);
00134       if(pix > 0 && gradient_direction == -1)
00135         sup_edge_image->set_pixel(x, y, pix);
00136 
00137     }
00138   }
00139 
00140   if(has_directory())
00141     save_normalized_image<TileImage_GS_DOUBLE>(join_pathes(get_directory(),
00142                                                            "04_non_max_suppression.tif"),
00143                                                sup_edge_image);
00144 }
00145 
00146 
00147 
00148     // returns the direction in degrees
00149 int CannyEdgeDetection::get_gradient_direction(TileImage_GS_DOUBLE_shptr horizontal_edges,
00150                                                TileImage_GS_DOUBLE_shptr vertical_edges,
00151                                                TileImage_GS_DOUBLE_shptr edge_mag_image,
00152                                                unsigned int x, unsigned int y) {
00153   double tangent = 5;
00154   // determine gradient direction
00155   if(vertical_edges->get_pixel(x, y) != 0)
00156     tangent = horizontal_edges->get_pixel(x, y) / vertical_edges->get_pixel(x, y);
00157 
00158   double
00159     nw = edge_mag_image->get_pixel(x - 1, y - 1),
00160     n  = edge_mag_image->get_pixel(x    , y - 1),
00161     ne = edge_mag_image->get_pixel(x + 1, y - 1),
00162     w  = edge_mag_image->get_pixel(x - 1, y    ),
00163     e  = edge_mag_image->get_pixel(x + 1, y    ),
00164     sw = edge_mag_image->get_pixel(x - 1, y + 1),
00165     s  = edge_mag_image->get_pixel(x    , y + 1),
00166     se = edge_mag_image->get_pixel(x + 1, y + 1),
00167     curr = edge_mag_image->get_pixel(x, y);
00168 
00169   // comment specifies gradient
00170   if(fabs(tangent) <= 0.4142) { // -
00171     if(curr < w && curr < nw && curr < sw) return 180;
00172     if(curr < e && curr < ne && curr < se) return 90;
00173     if(curr < w) return 180;
00174     if(curr < e) return 90;
00175   }
00176   if(0.4142 < tangent && tangent <= 2.4142) { //  /
00177     if(curr < ne && curr < n && curr < e) return 45;
00178     if(curr < sw && curr < s && curr < w) return 225;
00179     if(curr < ne) return 45;
00180     if(curr < sw) return 225;
00181   }
00182   if(fabs(tangent) > 2.4142) { //  |
00183     if(curr < n && curr < nw && curr < ne) return 90;
00184     if(curr < s && curr < sw && curr < se) return 270;
00185     if(curr < n) return 90;
00186     if(curr < s) return 270;
00187   }
00188   if(-2.4142 < tangent && tangent <= -0.4142) { //
00189     if(curr < nw && curr < n && curr < w) return 135;
00190     if(curr < se && curr < s && curr < e) return 315;
00191     if(curr < nw) return 135;
00192     if(curr < se) return 315;
00193   }
00194   return -1;
00195 }
00196