PTdecode/CImg-1.3.0/examples/edge_explorer.cpp

Tue, 18 Mar 2014 01:27:15 +0000

author
Philip Pemberton <philpem@philpem.me.uk>
date
Tue, 18 Mar 2014 01:27:15 +0000
changeset 23
f2c7acb4a258
parent 5
1204ebf9340d
permissions
-rwxr-xr-x

Update PTdecode to handle output from other Ptouch drivers

     1 /*
     2  #
     3  #  File        : edge_explorer.cpp
     4  #                ( C++ source file )
     5  #
     6  #  Description : Real time edge detection while moving a ROI
     7  #                (rectangle of interest) over the original image.
     8  #                This file is a part of the CImg Library project.
     9  #                ( http://cimg.sourceforge.net )
    10  #
    11  #  Copyright   : Orges Leka
    12  #                ( oleka(at)students.uni-mainz.de )
    13  #
    14  #  License     : CeCILL v2.0
    15  #                ( http://www.cecill.info/licences/Licence_CeCILL_V2-en.html )
    16  #
    17  #  This software is governed by the CeCILL  license under French law and
    18  #  abiding by the rules of distribution of free software.  You can  use,
    19  #  modify and/ or redistribute the software under the terms of the CeCILL
    20  #  license as circulated by CEA, CNRS and INRIA at the following URL
    21  #  "http://www.cecill.info".
    22  #
    23  #  As a counterpart to the access to the source code and  rights to copy,
    24  #  modify and redistribute granted by the license, users are provided only
    25  #  with a limited warranty  and the software's author,  the holder of the
    26  #  economic rights,  and the successive licensors  have only  limited
    27  #  liability.
    28  #
    29  #  In this respect, the user's attention is drawn to the risks associated
    30  #  with loading,  using,  modifying and/or developing or reproducing the
    31  #  software by the user in light of its specific status of free software,
    32  #  that may mean  that it is complicated to manipulate,  and  that  also
    33  #  therefore means  that it is reserved for developers  and  experienced
    34  #  professionals having in-depth computer knowledge. Users are therefore
    35  #  encouraged to load and test the software's suitability as regards their
    36  #  requirements in conditions enabling the security of their systems and/or
    37  #  data to be ensured and,  more generally, to use and operate it in the
    38  #  same conditions as regards security.
    39  #
    40  #  The fact that you are presently reading this means that you have had
    41  #  knowledge of the CeCILL license and that you accept its terms.
    42  #
    43 */
    45 #include "CImg.h"
    46 using namespace cimg_library;
    48 // The lines below are necessary when using a non-standard compiler as visualcpp6.
    49 #ifdef cimg_use_visualcpp6
    50 #define std
    51 #endif
    52 #ifdef min
    53 #undef min
    54 #undef max
    55 #endif
    57 #ifndef cimg_imagepath
    58 #define cimg_imagepath "img/"
    59 #endif
    61 // Start main procedure
    62 //-----------------------
    63 int main(int argc, char** argv) {
    65   // Usage of the program displayed at the command line
    66   cimg_usage("Real time edge detection with CImg. (c) Orges Leka");
    68   // Read command line arguments
    69   // With cimg_option we can get a new name for the image which is to be loaded from the command line.
    70   const char* img_name =  cimg_option("-i", cimg_imagepath "lena.pgm","Input image.");
    71   double
    72     alpha = cimg_option("-a",1.0,"Blurring the gradient image."),
    73     thresL = cimg_option("-tl",13.5,"Lower thresholding used in Hysteresis."),
    74     thresH = cimg_option("-th",13.6,"Higher thresholding used in Hysteresis.");
    75   const unsigned int
    76     mode = cimg_option("-m",1,"Detection mode: 1 = Hysteresis, 2 = Gradient angle."),
    77     factor = cimg_option("-s",80,"Half-size of edge-explorer window.");
    79   cimg_help("\nAdditional notes : user can press following keys on main display window :\n"
    80             "     - Left arrow : Decrease alpha.\n"
    81             "     - Right arrow : Increase alpha.\n");
    83   // Construct a new image called 'edge' of size (2*factor,2*factor)
    84   // and of type 'unsigned char'.
    85   CImg<unsigned char> edge(2*factor,2*factor);
    86   CImgDisplay disp_edge(512,512,"Edge Explorer");
    88   // Load the image with the name 'img_name' into the CImg 'img'.
    89   // and create a display window 'disp' for the image 'img'.
    90   const CImg<unsigned char> img(img_name);
    91   CImgDisplay disp(img,"Original Image");
    93   // Begin main interaction loop.
    94   int x = 0, y = 0;
    95   bool redraw = false;
    96   while (!disp.is_closed && !disp.is_keyQ && !disp.is_keyESC) {
    97     disp.wait(100);
    98     if (disp.button&1) { alpha+=0.05; redraw = true; }
    99     if (disp.button&2) { alpha-=0.05; redraw = true; }
   100     if (disp.wheel) { alpha+=0.05*disp.wheel; disp.wheel = 0; redraw = true; }
   101     if (alpha<0) alpha = 0;
   102     if (disp_edge.is_resized) { disp_edge.resize(); redraw = true; }
   103     if (disp_edge.is_closed) disp_edge.show();
   104     if (disp.is_resized) disp.resize(disp);
   105     if (disp.mouse_x>=0) {
   106       x = disp.mouse_x; // Getting the current position of the mouse.
   107       y = disp.mouse_y; //
   108       redraw = true;    // The image should be redrawn.
   109     }
   110     if (redraw) {
   111       disp_edge.set_title("Edge explorer (alpha=%g)",alpha);
   112       const int
   113         x0 = x-factor, y0 = y-factor,  // These are the coordinates for the red rectangle
   114         x1 = x+factor, y1 = y+factor;  // to be drawn on the original image.
   115       const unsigned char
   116         red[3] = { 255,0,0 },          //
   117         black[3] = { 0,0,0 };          // Defining the colors we need for drawing.
   119         (+img).draw_rectangle(x0,y0,x1,y1,red,1.0f,0x55555555U).display(disp);
   120         //^ We draw the red rectangle on the original window using 'draw_line'. Then we display the result via '.display(disp)' .
   121         //  Observe, that the color 'red' has to be of type 'const unsigned char',
   122         //  since the image 'img' is of type 'const CImg<unsigned char>'.
   124         //'normalize' is used to get a greyscaled image.
   125         CImg<> visu_bw = CImg<>(img).get_crop(x0,y0,x1,y1).get_pointwise_norm().normalize(0,255).resize(-100,-100,1,2,2);
   126         // get_crop(x0,y0,x1,y1) gets the rectangle we are interested in.
   128         edge.fill(255); // Background color in the edge-detection window is white.
   130         // grad[0] is the gradient image of 'visu_bw' in x-direction.
   131         // grad[1] is the gradient image of 'visu_bw' in y-direction.
   132         CImgList<> grad(visu_bw.blur((float)alpha).normalize(0,255).get_gradient());
   134         // To avoid unnecessary calculations in the image loops:
   135         const double
   136           pi = cimg::valuePI,
   137           p8 = pi/8.0, p38 = 3.0*p8,
   138           p58 = 5.0*p8, p78 = 7.0*p8;
   140         cimg_forXY(visu_bw,s,t) {
   141           // We take s,t instead of x,y, since x,y are already used.
   142           // s corresponds to the x-ordinate of the pixel while t corresponds to the y-ordinate.
   143           if ( 1 <= s && s <= visu_bw.dimx()-1 && 1 <= t && t <=visu_bw.dimy()-1) { // if - good points
   144             double
   145               Gs = grad[0](s,t),                  //
   146               Gt = grad[1](s,t),                               //  The actual pixel is (s,t)
   147               Gst = cimg::abs(Gs) + cimg::abs(Gt),    //
   148               // ^-- For efficient computation we observe that |Gs|+ |Gt| ~=~ sqrt( Gs^2 + Gt^2)
   149               Gr, Gur, Gu, Gul, Gl, Gdl, Gd, Gdr;
   150             // ^-- right, up right, up, up left, left, down left, down, down right.
   151             double theta = std::atan2(Gt,Gs)+pi; // theta is from the interval [0,Pi]
   152             switch(mode) {
   153             case 1: // Hysterese is applied
   154               if (Gst>=thresH) { edge.draw_point(s,t,black); }
   155               else if (thresL <= Gst && Gst < thresH) {
   156                 // Neighbourhood of the actual pixel:
   157                 Gr = cimg::abs(grad[0](s+1,t)) + cimg::abs(grad[1](s+1,t)); // right
   158                 Gl = cimg::abs(grad[0](s-1,t)) + cimg::abs(grad[1](s-1,t)); // left
   159                 Gur = cimg::abs(grad[0](s+1,t+1)) + cimg::abs(grad[1](s+1,t+1)); // up right
   160                 Gdl = cimg::abs(grad[0](s-1,t-1)) + cimg::abs(grad[1](s-1,t-1)); // down left
   161                 Gu = cimg::abs(grad[0](s,t+1)) + cimg::abs(grad[1](s,t+1)); // up
   162                 Gd = cimg::abs(grad[0](s,t-1)) + cimg::abs(grad[1](s,t-1)); // down
   163                 Gul = cimg::abs(grad[0](s-1,t+1)) + cimg::abs(grad[1](s-1,t+1)); // up left
   164                 Gdr = cimg::abs(grad[0](s+1,t-1)) + cimg::abs(grad[1](s+1,t-1)); // down right
   165                 if (Gr>=thresH || Gur>=thresH || Gu>=thresH || Gul>=thresH
   166                     || Gl>=thresH || Gdl >=thresH || Gu >=thresH || Gdr >=thresH) {
   167                   edge.draw_point(s,t,black);
   168                 }
   169               };
   170               break;
   171             case 2: // Angle 'theta' of the gradient (Gs,Gt) at the point (s,t).
   172               if(theta >= pi)theta-=pi;
   173               //rounding theta:
   174               if ((p8 < theta && theta <= p38 ) || (p78 < theta && theta <= pi)) {
   175                 // See (*) below for explanation of the vocabulary used.
   176                 // Direction-pixel is (s+1,t) with corresponding gradient value Gr.
   177                 Gr = cimg::abs(grad[0](s+1,t)) + cimg::abs(grad[1](s+1,t)); // right
   178                 // Contra-direction-pixel is (s-1,t) with corresponding gradient value Gl.
   179                 Gl = cimg::abs(grad[0](s-1,t)) + cimg::abs(grad[1](s-1,t)); // left
   180                 if (Gr < Gst && Gl < Gst) {
   181                   edge.draw_point(s,t,black);
   182                 }
   183               }
   184               else if ( p8 < theta && theta <= p38) {
   185                 // Direction-pixel is (s+1,t+1) with corresponding gradient value Gur.
   186                 Gur = cimg::abs(grad[0](s+1,t+1)) + cimg::abs(grad[1](s+1,t+1)); // up right
   187                 // Contra-direction-pixel is (s-1,t-1) with corresponding gradient value Gdl.
   188                 Gdl = cimg::abs(grad[0](s-1,t-1)) + cimg::abs(grad[1](s-1,t-1)); // down left
   189                 if (Gur < Gst && Gdl < Gst) {
   190                   edge.draw_point(s,t,black);
   191                       }
   192               }
   193               else if ( p38 < theta && theta <= p58) {
   194                 // Direction-pixel is (s,t+1) with corresponding gradient value Gu.
   195                 Gu = cimg::abs(grad[0](s,t+1)) + cimg::abs(grad[1](s,t+1)); // up
   196                 // Contra-direction-pixel is (s,t-1) with corresponding gradient value Gd.
   197                 Gd = cimg::abs(grad[0](s,t-1)) + cimg::abs(grad[1](s,t-1)); // down
   198                 if (Gu < Gst && Gd < Gst) {
   199                   edge.draw_point(s,t,black);
   200                 }
   201               }
   202               else if (p58 < theta && theta <= p78) {
   203                 // Direction-pixel is (s-1,t+1) with corresponding gradient value Gul.
   204                 Gul = cimg::abs(grad[0](s-1,t+1)) + cimg::abs(grad[1](s-1,t+1)); // up left
   205                 // Contra-direction-pixel is (s+1,t-1) with corresponding gradient value Gdr.
   206                 Gdr = cimg::abs(grad[0](s+1,t-1)) + cimg::abs(grad[1](s+1,t-1)); // down right
   207                 if (Gul < Gst && Gdr < Gst) {
   208                   edge.draw_point(s,t,black);
   209                 }
   210               };
   211               break;
   212             } // switch
   213           } // if good-points
   214         }  // cimg_forXY */
   215         edge.display(disp_edge);
   216     }// if redraw
   217   } // while
   218   return 0;
   219 }
   221 // (*) Comments to the vocabulary used:
   222 // If (s,t) is the current pixel, and G=(Gs,Gt) is the gradient at (s,t),
   223 // then the _direction_pixel_ of (s,t) shall be the one of the eight neighbour pixels
   224 // of (s,t) in whose direction the gradient G shows.
   225 // The _contra_direction_pixel is the pixel in the opposite direction in which the gradient G shows.
   226 // The _corresponding_gradient_value_ of the pixel (x,y) with gradient G = (Gx,Gy)
   227 // shall be |Gx|+|Gy| ~=~ sqrt(Gx^2+Gy^2).