MythTV  0.26-pre
CannyEdgeDetector.cpp
Go to the documentation of this file.
00001 // ANSI C headers
00002 #include <cmath>
00003 
00004 // MythTV headers
00005 #include "mythplayer.h"
00006 #include "frame.h"          // VideoFrame
00007 #include "mythlogging.h"
00008 
00009 // Commercial Flagging headers
00010 #include "pgm.h"
00011 #include "CannyEdgeDetector.h"
00012 
00013 using namespace edgeDetector;
00014 
00015 CannyEdgeDetector::CannyEdgeDetector(void)
00016     : sgm(NULL)
00017     , sgmsorted(NULL)
00018     , ewidth(-1)
00019     , eheight(-1)
00020 {
00021     /*
00022      * In general, the Gaussian mask is truncated at a point where values cease
00023      * to make any meaningful contribution. The sigma=>truncation computation
00024      * is best done by table lookup (which I don't have here). For sigma=0.5,
00025      * the magic truncation value is 4.
00026      */
00027     const int       TRUNCATION = 4;
00028     const double    sigma = 0.5;
00029     const double    TWO_SIGMA2 = 2 * sigma * sigma;
00030 
00031     double          val, sum;
00032     int             mask_width, rr, ii;
00033 
00034     /* The SGM computations require that mask_radius >= 2. */
00035     mask_radius = max(2, (int)roundf(TRUNCATION * sigma));
00036     mask_width = 2 * mask_radius + 1;
00037 
00038     /* Compute Gaussian mask. */
00039     mask = new double[mask_width];
00040     val = 1.0;  /* Initialize center of Gaussian mask (rr=0 => exp(0)). */
00041     mask[mask_radius] = val;
00042     sum = val;
00043     for (rr = 1; rr <= mask_radius; rr++)
00044     {
00045         val = exp(-(rr * rr) / TWO_SIGMA2); // Gaussian weight(rr,sigma)
00046         mask[mask_radius + rr] = val;
00047         mask[mask_radius - rr] = val;
00048         sum += 2 * val;
00049     }
00050     for (ii = 0; ii < mask_width; ii++)
00051         mask[ii] /= sum;    /* normalize to [0,1] */
00052 
00053     memset(&s1, 0, sizeof(s1));
00054     memset(&s2, 0, sizeof(s2));
00055     memset(&convolved, 0, sizeof(convolved));
00056     memset(&edges, 0, sizeof(edges));
00057     memset(&exclude, 0, sizeof(exclude));
00058 }
00059 
00060 CannyEdgeDetector::~CannyEdgeDetector(void)
00061 {
00062     avpicture_free(&edges);
00063     avpicture_free(&convolved);
00064     avpicture_free(&s2);
00065     avpicture_free(&s1);
00066     if (sgmsorted)
00067         delete []sgmsorted;
00068     if (sgm)
00069         delete []sgm;
00070     if (mask)
00071         delete []mask;
00072 }
00073 
00074 int
00075 CannyEdgeDetector::resetBuffers(int newwidth, int newheight)
00076 {
00077     if (ewidth == newwidth && eheight == newheight)
00078         return 0;
00079 
00080     if (sgm) {
00081         /*
00082          * Sentinel value to determine whether or not stuff has already been
00083          * allocated.
00084          */
00085         avpicture_free(&s1);
00086         avpicture_free(&s2);
00087         avpicture_free(&convolved);
00088         avpicture_free(&edges);
00089         delete []sgm;
00090         delete []sgmsorted;
00091         sgm = NULL;
00092     }
00093 
00094     const int   padded_width = newwidth + 2 * mask_radius;
00095     const int   padded_height = newheight + 2 * mask_radius;
00096 
00097     if (avpicture_alloc(&s1, PIX_FMT_GRAY8, padded_width, padded_height))
00098     {
00099         LOG(VB_COMMFLAG, LOG_ERR, "CannyEdgeDetector::resetBuffers "
00100                                   "avpicture_alloc s1 failed");
00101         return -1;
00102     }
00103 
00104     if (avpicture_alloc(&s2, PIX_FMT_GRAY8, padded_width, padded_height))
00105     {
00106         LOG(VB_COMMFLAG, LOG_ERR, "CannyEdgeDetector::resetBuffers "
00107                                   "avpicture_alloc s2 failed");
00108         goto free_s1;
00109     }
00110 
00111     if (avpicture_alloc(&convolved, PIX_FMT_GRAY8, padded_width, padded_height))
00112     {
00113         LOG(VB_COMMFLAG, LOG_ERR, "CannyEdgeDetector::resetBuffers "
00114                                   "avpicture_alloc convolved failed");
00115         goto free_s2;
00116     }
00117 
00118     if (avpicture_alloc(&edges, PIX_FMT_GRAY8, newwidth, newheight))
00119     {
00120         LOG(VB_COMMFLAG, LOG_ERR, "CannyEdgeDetector::resetBuffers "
00121                                   "avpicture_alloc edges failed");
00122         goto free_convolved;
00123     }
00124 
00125     sgm = new unsigned int[padded_width * padded_height];
00126     sgmsorted = new unsigned int[newwidth * newheight];
00127 
00128     ewidth = newwidth;
00129     eheight = newheight;
00130 
00131     return 0;
00132 
00133 free_convolved:
00134     avpicture_free(&convolved);
00135 free_s2:
00136     avpicture_free(&s2);
00137 free_s1:
00138     avpicture_free(&s1);
00139     return -1;
00140 }
00141 
00142 int
00143 CannyEdgeDetector::setExcludeArea(int row, int col, int width, int height)
00144 {
00145     exclude.row = row;
00146     exclude.col = col;
00147     exclude.width = width;
00148     exclude.height = height;
00149     return 0;
00150 }
00151 
00152 const AVPicture *
00153 CannyEdgeDetector::detectEdges(const AVPicture *pgm, int pgmheight,
00154         int percentile)
00155 {
00156     /*
00157      * Canny edge detection
00158      *
00159      * See
00160      * http://www.cs.cornell.edu/courses/CS664/2003fa/handouts/664-l6-edges-03.pdf
00161      */
00162 
00163     const int   pgmwidth = pgm->linesize[0];
00164     const int   padded_height = pgmheight + 2 * mask_radius;
00165 
00166     if (resetBuffers(pgmwidth, pgmheight))
00167         return NULL;
00168 
00169     if (pgm_convolve_radial(&convolved, &s1, &s2, pgm, pgmheight,
00170                 mask, mask_radius))
00171         return NULL;
00172 
00173     if (edge_mark_uniform_exclude(&edges, pgmheight, mask_radius,
00174                 sgm_init_exclude(sgm, &convolved, padded_height,
00175                     exclude.row + mask_radius, exclude.col + mask_radius,
00176                     exclude.width, exclude.height),
00177                 sgmsorted, percentile,
00178                 exclude.row, exclude.col, exclude.width, exclude.height))
00179         return NULL;
00180 
00181     return &edges;
00182 }
00183 
00184 /* vim: set expandtab tabstop=4 shiftwidth=4: */
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends