degate  0.1.2
MorphologicalFilter.h
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 #ifndef __MORPHOLOGICALFILTER_H__
00023 #define __MORPHOLOGICALFILTER_H__
00024 
00025 namespace degate {
00026 
00027   /**
00028    * Policy class for image erosion.
00029    * This policy class can be used for any single channel image. Pixel values
00030    * evaluate to 0 if they are <= 0 and evaluated to 1 if they are > 0.
00031    */
00032   template<typename ImageType, typename PixelType>
00033   struct ErodeImagePolicy {
00034 
00035     static inline PixelType calculate(std::shared_ptr<ImageType> src,
00036                                       unsigned int x, unsigned int y,
00037                                       unsigned int min_x,
00038                                       unsigned int max_x,
00039                                       unsigned int min_y,
00040                                       unsigned int max_y,
00041                                       unsigned int erosion_threshold) {
00042 
00043       assert(min_x < max_x && min_y < max_y);
00044       assert(min_x < src->get_width());
00045       assert(max_x < src->get_width());
00046       assert(min_y < src->get_height());
00047       assert(max_y < src->get_height());
00048 
00049       unsigned int i = 0;
00050 
00051       for(unsigned int _y = min_y; _y < max_y; _y++)
00052         for(unsigned int _x = min_x; _x < max_x; _x++)
00053           if(src->get_pixel(_x, _y) > 0) i++;
00054 
00055       return i <= erosion_threshold ? 0 : src->get_pixel(x, y);
00056     }
00057   };
00058 
00059 
00060   /**
00061    * Filter an image with an erosion filter.
00062    */
00063 
00064   template<typename ImageTypeDst, typename ImageTypeSrc>
00065   void erode_image(std::shared_ptr<ImageTypeDst> dst,
00066                    std::shared_ptr<ImageTypeSrc> src,
00067                    unsigned int kernel_width = 3,
00068                    unsigned int erosion_threshold = 3) {
00069 
00070     filter_image<ImageTypeDst, ImageTypeSrc,
00071       ErodeImagePolicy<ImageTypeSrc, typename ImageTypeSrc::pixel_type> >
00072       (dst, src, kernel_width, erosion_threshold);
00073   }
00074 
00075 
00076   /**
00077    * Policy class for image dilation.
00078    * This policy class can be used for any single channel image. Pixel values
00079    * evaluate to 0 if they are <= 0 and evaluated to 1 if they are > 0.
00080    */
00081   template<typename ImageType, typename PixelType>
00082   struct DilateImagePolicy {
00083 
00084     static inline PixelType calculate(std::shared_ptr<ImageType> src,
00085                                       unsigned int x, unsigned int y,
00086                                       unsigned int min_x,
00087                                       unsigned int max_x,
00088                                       unsigned int min_y,
00089                                       unsigned int max_y,
00090                                       unsigned int dilation_threshold) {
00091 
00092       assert(min_x < max_x && min_y < max_y);
00093       assert(min_x < src->get_width());
00094       assert(max_x < src->get_width());
00095       assert(min_y < src->get_height());
00096       assert(max_y < src->get_height());
00097 
00098       unsigned int i = 0;
00099 
00100       for(unsigned int _y = min_y; _y < max_y; _y++)
00101         for(unsigned int _x = min_x; _x < max_x; _x++)
00102           if(src->get_pixel(_x, _y) > 0) i++;
00103       return i >= dilation_threshold ? 1 : src->get_pixel(x, y);
00104     }
00105   };
00106 
00107 
00108   /**
00109    * Filter an image with an erosion filter.
00110    */
00111 
00112   template<typename ImageTypeDst, typename ImageTypeSrc>
00113   void dilate_image(std::shared_ptr<ImageTypeDst> dst,
00114                     std::shared_ptr<ImageTypeSrc> src,
00115                     unsigned int kernel_width = 3,
00116                     unsigned int dilation_threshold = 3) {
00117 
00118     filter_image<ImageTypeDst, ImageTypeSrc,
00119       DilateImagePolicy<ImageTypeSrc, typename ImageTypeSrc::pixel_type> >
00120       (dst, src, kernel_width, dilation_threshold);
00121   }
00122 
00123 
00124   /**
00125    * Morphological open.
00126    */
00127   template<typename ImageTypeDst, typename ImageTypeSrc>
00128   void morphological_open(std::shared_ptr<ImageTypeDst> dst,
00129                           std::shared_ptr<ImageTypeSrc> src, 
00130                           unsigned int kernel_width = 3,
00131                           unsigned int threshold_dilate = 1,
00132                           unsigned int threshold_erode = 3) {
00133 
00134     filter_image<ImageTypeDst, ImageTypeSrc,
00135       ErodeImagePolicy<ImageTypeSrc, typename ImageTypeSrc::pixel_type> >(dst, src, kernel_width, threshold_erode);
00136 
00137     filter_image<ImageTypeDst, ImageTypeSrc,
00138       DilateImagePolicy<ImageTypeSrc, typename ImageTypeSrc::pixel_type> >(dst, src, kernel_width, threshold_dilate);
00139   }
00140 
00141 
00142   /**
00143    * Morphological close.
00144    */
00145   template<typename ImageTypeDst, typename ImageTypeSrc>
00146   void morphological_close(std::shared_ptr<ImageTypeDst> dst,
00147                            std::shared_ptr<ImageTypeSrc> src,
00148                            unsigned int kernel_width = 3,
00149                            unsigned int threshold_dilate = 1,
00150                            unsigned int threshold_erode = 3) {
00151 
00152     filter_image<ImageTypeDst, ImageTypeSrc,
00153       DilateImagePolicy<ImageTypeSrc, typename ImageTypeSrc::pixel_type> >(dst, src, kernel_width, threshold_dilate);
00154 
00155     filter_image<ImageTypeDst, ImageTypeSrc,
00156       ErodeImagePolicy<ImageTypeSrc, typename ImageTypeSrc::pixel_type> >(dst, src, kernel_width, threshold_erode);
00157 
00158   }
00159 
00160 
00161   /**
00162    * Helper function for the Zhang-Suen-Thinning.
00163    * @param img The image.
00164    * @param condition_switch If true, the first condition set is checked. If false,
00165    *   the second condition set is checked.
00166    */
00167   template<typename ImageType>
00168   bool zhang_suen_thinning_iteration(std::shared_ptr<ImageType> img,
00169                                      bool condition_switch) {
00170     assert_is_single_channel_image<ImageType>();
00171 
00172     bool running = false;
00173     unsigned int x, y;
00174 
00175     for(y = 1; y < img->get_height() - 1; y++) {
00176       for(x = 1; x < img->get_width() - 1; x++) {
00177         unsigned int
00178           p1 = img->get_pixel(x, y) > 0 ? 1 : 0;
00179 
00180         if(p1 > 0) {
00181           unsigned int
00182             p2 = img->get_pixel(x, y-1) > 0 ? 1 : 0,
00183             p3 = img->get_pixel(x+1, y-1) > 0 ? 1 : 0,
00184             p4 = img->get_pixel(x+1, y) > 0 ? 1 : 0,
00185             p5 = img->get_pixel(x+1, y+1) > 0 ? 1 : 0,
00186             p6 = img->get_pixel(x, y+1) > 0 ? 1 : 0,
00187             p7 = img->get_pixel(x-1, y+1) > 0 ? 1 : 0,
00188             p8 = img->get_pixel(x-1, y) > 0 ? 1 : 0,
00189             p9 = img->get_pixel(x-1, y-1)> 0 ? 1 : 0;
00190 
00191           unsigned int connectivity =
00192             (p2 == 0 && p3 == 1 ? 1 : 0) +
00193             (p3 == 0 && p4 == 1 ? 1 : 0) +
00194             (p4 == 0 && p5 == 1 ? 1 : 0) +
00195             (p5 == 0 && p6 == 1 ? 1 : 0) +
00196             (p6 == 0 && p7 == 1 ? 1 : 0) +
00197             (p7 == 0 && p8 == 1 ? 1 : 0) +
00198             (p8 == 0 && p9 == 1 ? 1 : 0) +
00199             (p9 == 0 && p2 == 1 ? 1 : 0);
00200 
00201           unsigned int non_zero_neighbors = p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9;
00202 
00203 
00204           if(2 <= non_zero_neighbors && non_zero_neighbors <= 6 &&
00205              connectivity == 1) {
00206 
00207             if(condition_switch == true) {
00208 
00209               if(p2 * p4 * p6 == 0 && p4 * p6 * p8 == 0) {
00210                 img->set_pixel(x, y, 0);
00211                 running = true;
00212               }
00213             }
00214             else {
00215               if(p2 * p4 * p8 == 0 && p2 * p6 * p8 == 0) {
00216                 img->set_pixel(x, y, 0);
00217                 running = true;
00218               }
00219             }
00220           }
00221         }
00222 
00223       }
00224     }
00225 
00226     return running;
00227   }
00228 
00229   /**
00230    * Zhang-Suen-Thinning of an image.
00231    */
00232   template<typename ImageType>
00233   void thinning(std::shared_ptr<ImageType> img) {
00234     assert_is_single_channel_image<ImageType>();
00235 
00236     bool running = true;
00237 
00238     do {
00239       running = zhang_suen_thinning_iteration(img, true);
00240       running = zhang_suen_thinning_iteration(img, false);
00241     }while(running);
00242 
00243   }
00244 
00245 
00246 }
00247 #endif