1.1 diff -r 5edfbd3e7a46 -r 1204ebf9340d PTdecode/CImg-1.3.0/examples/edge_explorer.cpp 1.2 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.3 +++ b/PTdecode/CImg-1.3.0/examples/edge_explorer.cpp Mon Aug 03 14:09:20 2009 +0100 1.4 @@ -0,0 +1,227 @@ 1.5 +/* 1.6 + # 1.7 + # File : edge_explorer.cpp 1.8 + # ( C++ source file ) 1.9 + # 1.10 + # Description : Real time edge detection while moving a ROI 1.11 + # (rectangle of interest) over the original image. 1.12 + # This file is a part of the CImg Library project. 1.13 + # ( http://cimg.sourceforge.net ) 1.14 + # 1.15 + # Copyright : Orges Leka 1.16 + # ( oleka(at)students.uni-mainz.de ) 1.17 + # 1.18 + # License : CeCILL v2.0 1.19 + # ( http://www.cecill.info/licences/Licence_CeCILL_V2-en.html ) 1.20 + # 1.21 + # This software is governed by the CeCILL license under French law and 1.22 + # abiding by the rules of distribution of free software. You can use, 1.23 + # modify and/ or redistribute the software under the terms of the CeCILL 1.24 + # license as circulated by CEA, CNRS and INRIA at the following URL 1.25 + # "http://www.cecill.info". 1.26 + # 1.27 + # As a counterpart to the access to the source code and rights to copy, 1.28 + # modify and redistribute granted by the license, users are provided only 1.29 + # with a limited warranty and the software's author, the holder of the 1.30 + # economic rights, and the successive licensors have only limited 1.31 + # liability. 1.32 + # 1.33 + # In this respect, the user's attention is drawn to the risks associated 1.34 + # with loading, using, modifying and/or developing or reproducing the 1.35 + # software by the user in light of its specific status of free software, 1.36 + # that may mean that it is complicated to manipulate, and that also 1.37 + # therefore means that it is reserved for developers and experienced 1.38 + # professionals having in-depth computer knowledge. Users are therefore 1.39 + # encouraged to load and test the software's suitability as regards their 1.40 + # requirements in conditions enabling the security of their systems and/or 1.41 + # data to be ensured and, more generally, to use and operate it in the 1.42 + # same conditions as regards security. 1.43 + # 1.44 + # The fact that you are presently reading this means that you have had 1.45 + # knowledge of the CeCILL license and that you accept its terms. 1.46 + # 1.47 +*/ 1.48 + 1.49 +#include "CImg.h" 1.50 +using namespace cimg_library; 1.51 + 1.52 +// The lines below are necessary when using a non-standard compiler as visualcpp6. 1.53 +#ifdef cimg_use_visualcpp6 1.54 +#define std 1.55 +#endif 1.56 +#ifdef min 1.57 +#undef min 1.58 +#undef max 1.59 +#endif 1.60 + 1.61 +#ifndef cimg_imagepath 1.62 +#define cimg_imagepath "img/" 1.63 +#endif 1.64 + 1.65 +// Start main procedure 1.66 +//----------------------- 1.67 +int main(int argc, char** argv) { 1.68 + 1.69 + // Usage of the program displayed at the command line 1.70 + cimg_usage("Real time edge detection with CImg. (c) Orges Leka"); 1.71 + 1.72 + // Read command line arguments 1.73 + // With cimg_option we can get a new name for the image which is to be loaded from the command line. 1.74 + const char* img_name = cimg_option("-i", cimg_imagepath "lena.pgm","Input image."); 1.75 + double 1.76 + alpha = cimg_option("-a",1.0,"Blurring the gradient image."), 1.77 + thresL = cimg_option("-tl",13.5,"Lower thresholding used in Hysteresis."), 1.78 + thresH = cimg_option("-th",13.6,"Higher thresholding used in Hysteresis."); 1.79 + const unsigned int 1.80 + mode = cimg_option("-m",1,"Detection mode: 1 = Hysteresis, 2 = Gradient angle."), 1.81 + factor = cimg_option("-s",80,"Half-size of edge-explorer window."); 1.82 + 1.83 + cimg_help("\nAdditional notes : user can press following keys on main display window :\n" 1.84 + " - Left arrow : Decrease alpha.\n" 1.85 + " - Right arrow : Increase alpha.\n"); 1.86 + 1.87 + // Construct a new image called 'edge' of size (2*factor,2*factor) 1.88 + // and of type 'unsigned char'. 1.89 + CImg<unsigned char> edge(2*factor,2*factor); 1.90 + CImgDisplay disp_edge(512,512,"Edge Explorer"); 1.91 + 1.92 + // Load the image with the name 'img_name' into the CImg 'img'. 1.93 + // and create a display window 'disp' for the image 'img'. 1.94 + const CImg<unsigned char> img(img_name); 1.95 + CImgDisplay disp(img,"Original Image"); 1.96 + 1.97 + // Begin main interaction loop. 1.98 + int x = 0, y = 0; 1.99 + bool redraw = false; 1.100 + while (!disp.is_closed && !disp.is_keyQ && !disp.is_keyESC) { 1.101 + disp.wait(100); 1.102 + if (disp.button&1) { alpha+=0.05; redraw = true; } 1.103 + if (disp.button&2) { alpha-=0.05; redraw = true; } 1.104 + if (disp.wheel) { alpha+=0.05*disp.wheel; disp.wheel = 0; redraw = true; } 1.105 + if (alpha<0) alpha = 0; 1.106 + if (disp_edge.is_resized) { disp_edge.resize(); redraw = true; } 1.107 + if (disp_edge.is_closed) disp_edge.show(); 1.108 + if (disp.is_resized) disp.resize(disp); 1.109 + if (disp.mouse_x>=0) { 1.110 + x = disp.mouse_x; // Getting the current position of the mouse. 1.111 + y = disp.mouse_y; // 1.112 + redraw = true; // The image should be redrawn. 1.113 + } 1.114 + if (redraw) { 1.115 + disp_edge.set_title("Edge explorer (alpha=%g)",alpha); 1.116 + const int 1.117 + x0 = x-factor, y0 = y-factor, // These are the coordinates for the red rectangle 1.118 + x1 = x+factor, y1 = y+factor; // to be drawn on the original image. 1.119 + const unsigned char 1.120 + red[3] = { 255,0,0 }, // 1.121 + black[3] = { 0,0,0 }; // Defining the colors we need for drawing. 1.122 + 1.123 + (+img).draw_rectangle(x0,y0,x1,y1,red,1.0f,0x55555555U).display(disp); 1.124 + //^ We draw the red rectangle on the original window using 'draw_line'. Then we display the result via '.display(disp)' . 1.125 + // Observe, that the color 'red' has to be of type 'const unsigned char', 1.126 + // since the image 'img' is of type 'const CImg<unsigned char>'. 1.127 + 1.128 + //'normalize' is used to get a greyscaled image. 1.129 + CImg<> visu_bw = CImg<>(img).get_crop(x0,y0,x1,y1).get_pointwise_norm().normalize(0,255).resize(-100,-100,1,2,2); 1.130 + // get_crop(x0,y0,x1,y1) gets the rectangle we are interested in. 1.131 + 1.132 + edge.fill(255); // Background color in the edge-detection window is white. 1.133 + 1.134 + // grad[0] is the gradient image of 'visu_bw' in x-direction. 1.135 + // grad[1] is the gradient image of 'visu_bw' in y-direction. 1.136 + CImgList<> grad(visu_bw.blur((float)alpha).normalize(0,255).get_gradient()); 1.137 + 1.138 + // To avoid unnecessary calculations in the image loops: 1.139 + const double 1.140 + pi = cimg::valuePI, 1.141 + p8 = pi/8.0, p38 = 3.0*p8, 1.142 + p58 = 5.0*p8, p78 = 7.0*p8; 1.143 + 1.144 + cimg_forXY(visu_bw,s,t) { 1.145 + // We take s,t instead of x,y, since x,y are already used. 1.146 + // s corresponds to the x-ordinate of the pixel while t corresponds to the y-ordinate. 1.147 + if ( 1 <= s && s <= visu_bw.dimx()-1 && 1 <= t && t <=visu_bw.dimy()-1) { // if - good points 1.148 + double 1.149 + Gs = grad[0](s,t), // 1.150 + Gt = grad[1](s,t), // The actual pixel is (s,t) 1.151 + Gst = cimg::abs(Gs) + cimg::abs(Gt), // 1.152 + // ^-- For efficient computation we observe that |Gs|+ |Gt| ~=~ sqrt( Gs^2 + Gt^2) 1.153 + Gr, Gur, Gu, Gul, Gl, Gdl, Gd, Gdr; 1.154 + // ^-- right, up right, up, up left, left, down left, down, down right. 1.155 + double theta = std::atan2(Gt,Gs)+pi; // theta is from the interval [0,Pi] 1.156 + switch(mode) { 1.157 + case 1: // Hysterese is applied 1.158 + if (Gst>=thresH) { edge.draw_point(s,t,black); } 1.159 + else if (thresL <= Gst && Gst < thresH) { 1.160 + // Neighbourhood of the actual pixel: 1.161 + Gr = cimg::abs(grad[0](s+1,t)) + cimg::abs(grad[1](s+1,t)); // right 1.162 + Gl = cimg::abs(grad[0](s-1,t)) + cimg::abs(grad[1](s-1,t)); // left 1.163 + Gur = cimg::abs(grad[0](s+1,t+1)) + cimg::abs(grad[1](s+1,t+1)); // up right 1.164 + Gdl = cimg::abs(grad[0](s-1,t-1)) + cimg::abs(grad[1](s-1,t-1)); // down left 1.165 + Gu = cimg::abs(grad[0](s,t+1)) + cimg::abs(grad[1](s,t+1)); // up 1.166 + Gd = cimg::abs(grad[0](s,t-1)) + cimg::abs(grad[1](s,t-1)); // down 1.167 + Gul = cimg::abs(grad[0](s-1,t+1)) + cimg::abs(grad[1](s-1,t+1)); // up left 1.168 + Gdr = cimg::abs(grad[0](s+1,t-1)) + cimg::abs(grad[1](s+1,t-1)); // down right 1.169 + if (Gr>=thresH || Gur>=thresH || Gu>=thresH || Gul>=thresH 1.170 + || Gl>=thresH || Gdl >=thresH || Gu >=thresH || Gdr >=thresH) { 1.171 + edge.draw_point(s,t,black); 1.172 + } 1.173 + }; 1.174 + break; 1.175 + case 2: // Angle 'theta' of the gradient (Gs,Gt) at the point (s,t). 1.176 + if(theta >= pi)theta-=pi; 1.177 + //rounding theta: 1.178 + if ((p8 < theta && theta <= p38 ) || (p78 < theta && theta <= pi)) { 1.179 + // See (*) below for explanation of the vocabulary used. 1.180 + // Direction-pixel is (s+1,t) with corresponding gradient value Gr. 1.181 + Gr = cimg::abs(grad[0](s+1,t)) + cimg::abs(grad[1](s+1,t)); // right 1.182 + // Contra-direction-pixel is (s-1,t) with corresponding gradient value Gl. 1.183 + Gl = cimg::abs(grad[0](s-1,t)) + cimg::abs(grad[1](s-1,t)); // left 1.184 + if (Gr < Gst && Gl < Gst) { 1.185 + edge.draw_point(s,t,black); 1.186 + } 1.187 + } 1.188 + else if ( p8 < theta && theta <= p38) { 1.189 + // Direction-pixel is (s+1,t+1) with corresponding gradient value Gur. 1.190 + Gur = cimg::abs(grad[0](s+1,t+1)) + cimg::abs(grad[1](s+1,t+1)); // up right 1.191 + // Contra-direction-pixel is (s-1,t-1) with corresponding gradient value Gdl. 1.192 + Gdl = cimg::abs(grad[0](s-1,t-1)) + cimg::abs(grad[1](s-1,t-1)); // down left 1.193 + if (Gur < Gst && Gdl < Gst) { 1.194 + edge.draw_point(s,t,black); 1.195 + } 1.196 + } 1.197 + else if ( p38 < theta && theta <= p58) { 1.198 + // Direction-pixel is (s,t+1) with corresponding gradient value Gu. 1.199 + Gu = cimg::abs(grad[0](s,t+1)) + cimg::abs(grad[1](s,t+1)); // up 1.200 + // Contra-direction-pixel is (s,t-1) with corresponding gradient value Gd. 1.201 + Gd = cimg::abs(grad[0](s,t-1)) + cimg::abs(grad[1](s,t-1)); // down 1.202 + if (Gu < Gst && Gd < Gst) { 1.203 + edge.draw_point(s,t,black); 1.204 + } 1.205 + } 1.206 + else if (p58 < theta && theta <= p78) { 1.207 + // Direction-pixel is (s-1,t+1) with corresponding gradient value Gul. 1.208 + Gul = cimg::abs(grad[0](s-1,t+1)) + cimg::abs(grad[1](s-1,t+1)); // up left 1.209 + // Contra-direction-pixel is (s+1,t-1) with corresponding gradient value Gdr. 1.210 + Gdr = cimg::abs(grad[0](s+1,t-1)) + cimg::abs(grad[1](s+1,t-1)); // down right 1.211 + if (Gul < Gst && Gdr < Gst) { 1.212 + edge.draw_point(s,t,black); 1.213 + } 1.214 + }; 1.215 + break; 1.216 + } // switch 1.217 + } // if good-points 1.218 + } // cimg_forXY */ 1.219 + edge.display(disp_edge); 1.220 + }// if redraw 1.221 + } // while 1.222 + return 0; 1.223 +} 1.224 + 1.225 +// (*) Comments to the vocabulary used: 1.226 +// If (s,t) is the current pixel, and G=(Gs,Gt) is the gradient at (s,t), 1.227 +// then the _direction_pixel_ of (s,t) shall be the one of the eight neighbour pixels 1.228 +// of (s,t) in whose direction the gradient G shows. 1.229 +// The _contra_direction_pixel is the pixel in the opposite direction in which the gradient G shows. 1.230 +// The _corresponding_gradient_value_ of the pixel (x,y) with gradient G = (Gx,Gy) 1.231 +// shall be |Gx|+|Gy| ~=~ sqrt(Gx^2+Gy^2).