MythTV  0.26-pre
EdgeDetector.cpp
Go to the documentation of this file.
00001 // ANSI C headers
00002 #include <cstdlib>
00003 
00004 // C++ headers
00005 #include <algorithm>
00006 using namespace std;
00007 
00008 #include "mythconfig.h"
00009 
00010 // avlib/ffmpeg headers
00011 extern "C" {
00012 #include "libavcodec/avcodec.h"        // AVPicture
00013 }
00014 
00015 // MythTV headers
00016 #include "frame.h"          // VideoFrame
00017 #include "mythplayer.h"
00018 
00019 // Commercial Flagging headers
00020 #include "FrameAnalyzer.h"
00021 #include "EdgeDetector.h"
00022 
00023 namespace edgeDetector {
00024 
00025 using namespace frameAnalyzer;
00026 
00027 unsigned int *
00028 sgm_init_exclude(unsigned int *sgm, const AVPicture *src, int srcheight,
00029         int excluderow, int excludecol, int excludewidth, int excludeheight)
00030 {
00031     /*
00032      * Squared Gradient Magnitude (SGM) calculations: use a 45-degree rotated
00033      * set of axes.
00034      *
00035      * Intuitively, the SGM of a pixel is a measure of the "edge intensity" of
00036      * that pixel: how much it differs from its neighbors.
00037      */
00038     const int       srcwidth = src->linesize[0];
00039     int             rr, cc, dx, dy, rr2, cc2;
00040     unsigned char   *rr0, *rr1;
00041 
00042     memset(sgm, 0, srcwidth * srcheight * sizeof(*sgm));
00043     rr2 = srcheight - 1;
00044     cc2 = srcwidth - 1;
00045     for (rr = 0; rr < rr2; rr++)
00046     {
00047         for (cc = 0; cc < cc2; cc++)
00048         {
00049             if (!rrccinrect(rr, cc, excluderow, excludecol,
00050                         excludewidth, excludeheight))
00051             {
00052                 rr0 = &src->data[0][rr * srcwidth + cc];
00053                 rr1 = &src->data[0][(rr + 1) * srcwidth + cc];
00054                 dx = rr1[1] - rr0[0];   /* southeast - northwest */
00055                 dy = rr1[0] - rr0[1];   /* southwest - northeast */
00056                 sgm[rr * srcwidth + cc] = dx * dx + dy * dy;
00057             }
00058         }
00059     }
00060     return sgm;
00061 }
00062 
00063 #ifdef LATER
00064 unsigned int *
00065 sgm_init(unsigned int *sgm, const AVPicture *src, int srcheight)
00066 {
00067     return sgm_init_exclude(sgm, src, srcheight, 0, 0, 0, 0);
00068 }
00069 #endif /* LATER */
00070 
00071 static int sort_ascending(const void *aa, const void *bb)
00072 {
00073     return *(unsigned int*)aa - *(unsigned int*)bb;
00074 }
00075 
00076 static int
00077 edge_mark(AVPicture *dst, int dstheight,
00078         int extratop, int extraright, int extrabottom, int extraleft,
00079         const unsigned int *sgm, unsigned int *sgmsorted, int percentile,
00080         int excluderow, int excludecol, int excludewidth, int excludeheight)
00081 {
00082     /*
00083      * TUNABLE:
00084      *
00085      * Conventionally, the Canny edge detector should select for intensities at
00086      * the 95th percentile or higher. In case the requested percentile actually
00087      * yields something lower (degenerate cases), pick the next unique
00088      * intensity, to try to salvage useful data.
00089      */
00090     static const int    MINTHRESHOLDPCT = 95;
00091 
00092     const int           dstwidth = dst->linesize[0];
00093     const int           padded_width = extraleft + dstwidth + extraright;
00094     unsigned int        thresholdval;
00095     int                 nn, dstnn, ii, rr, cc, first, last, last2;
00096 
00097     (void)extrabottom;  /* gcc */
00098 
00099     /*
00100      * sgm: SGM values of padded (convolved) image
00101      *
00102      * sgmsorted: sorted SGM values of unexcluded areas of unpadded image (same
00103      * dimensions as "dst").
00104      */
00105     nn = 0;
00106     for (rr = 0; rr < dstheight; rr++)
00107     {
00108         for (cc = 0; cc < dstwidth; cc++)
00109         {
00110             if (!rrccinrect(rr, cc, excluderow, excludecol,
00111                         excludewidth, excludeheight))
00112             {
00113                 sgmsorted[nn++] = sgm[(extratop + rr) * padded_width +
00114                     extraleft + cc];
00115             }
00116         }
00117     }
00118 
00119     dstnn = dstwidth * dstheight;
00120 #if 0
00121     assert(nn == dstnn -
00122             (min(max(0, excluderow + excludeheight), dstheight) -
00123                 min(max(0, excluderow), dstheight)) *
00124             (min(max(0, excludecol + excludewidth), dstwidth) -
00125                 min(max(0, excludecol), dstwidth)));
00126 #endif
00127     memset(dst->data[0], 0, dstnn * sizeof(*dst->data[0]));
00128 
00129     if (!nn)
00130     {
00131             /* Degenerate case (entire area excluded from analysis). */
00132             return 0;
00133     }
00134 
00135     qsort(sgmsorted, nn, sizeof(*sgmsorted), sort_ascending);
00136 
00137     ii = percentile * nn / 100;
00138     thresholdval = sgmsorted[ii];
00139 
00140     /*
00141      * Try not to pick up too many edges, and eliminate degenerate edge-less
00142      * cases.
00143      */
00144     for (first = ii; first > 0 && sgmsorted[first] == thresholdval; first--) ;
00145     if (sgmsorted[first] != thresholdval)
00146         first++;
00147     if (first * 100 / nn < MINTHRESHOLDPCT)
00148     {
00149         unsigned int    newthresholdval;
00150 
00151         last2 = nn - 1;
00152         for (last = ii; last < last2 && sgmsorted[last] == thresholdval;
00153                 last++) ;
00154         if (sgmsorted[last] != thresholdval)
00155             last--;
00156 
00157         newthresholdval = sgmsorted[min(last + 1, nn - 1)];
00158         if (thresholdval == newthresholdval)
00159         {
00160             /* Degenerate case; no edges (e.g., blank frame). */
00161             return 0;
00162         }
00163 
00164         thresholdval = newthresholdval;
00165     }
00166 
00167     /* sgm is a padded matrix; dst is the unpadded matrix. */
00168     for (rr = 0; rr < dstheight; rr++)
00169     {
00170         for (cc = 0; cc < dstwidth; cc++)
00171         {
00172             if (!rrccinrect(rr, cc, excluderow, excludecol,
00173                         excludewidth, excludeheight) &&
00174                     sgm[(extratop + rr) * padded_width + extraleft + cc] >=
00175                         thresholdval)
00176                 dst->data[0][rr * dstwidth + cc] = UCHAR_MAX;
00177         }
00178     }
00179     return 0;
00180 }
00181 
00182 #ifdef LATER
00183 int edge_mark_uniform(AVPicture *dst, int dstheight, int extramargin,
00184         const unsigned int *sgm, unsigned int *sgmsorted,
00185         int percentile)
00186 {
00187     return edge_mark(dst, dstheight,
00188             extramargin, extramargin, extramargin, extramargin,
00189             sgm, sgmsorted, percentile, 0, 0, 0, 0);
00190 }
00191 #endif /* LATER */
00192 
00193 int edge_mark_uniform_exclude(AVPicture *dst, int dstheight, int extramargin,
00194         const unsigned int *sgm, unsigned int *sgmsorted, int percentile,
00195         int excluderow, int excludecol, int excludewidth, int excludeheight)
00196 {
00197     return edge_mark(dst, dstheight,
00198             extramargin, extramargin, extramargin, extramargin,
00199             sgm, sgmsorted, percentile,
00200             excluderow, excludecol, excludewidth, excludeheight);
00201 }
00202 
00203 };  /* namespace */
00204 
00205 EdgeDetector::~EdgeDetector(void)
00206 {
00207 }
00208 
00209 int
00210 EdgeDetector::setExcludeArea(int row, int col, int width, int height)
00211 {
00212     (void)row;  /* gcc */
00213     (void)col;  /* gcc */
00214     (void)width;    /* gcc */
00215     (void)height;   /* gcc */
00216     return 0;
00217 }
00218 
00219 /* vim: set expandtab tabstop=4 shiftwidth=4: */
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends