|
MythTV
0.26-pre
|
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: */
1.7.6.1