MythTV  master
CannyEdgeDetector.cpp
Go to the documentation of this file.
1 // C++ headers
2 #include <cmath>
3 
4 // MythTV headers
7 #include "libmythtv/mythframe.h" // VideoFrame
8 #include "libmythtv/mythplayer.h"
9 
10 // Commercial Flagging headers
11 #include "CannyEdgeDetector.h"
12 #include "pgm.h"
13 
14 extern "C" {
15 #include "libavutil/imgutils.h"
16 }
17 
18 using namespace edgeDetector;
19 
21 {
22  /*
23  * In general, the Gaussian mask is truncated at a point where values cease
24  * to make any meaningful contribution. The sigma=>truncation computation
25  * is best done by table lookup (which I don't have here). For sigma=0.5,
26  * the magic truncation value is 4.
27  */
28  const int TRUNCATION = 4;
29  const double sigma = 0.5;
30  const double TWO_SIGMA2 = 2 * sigma * sigma;
31 
32  /* The SGM computations require that mask_radius >= 2. */
33  m_maskRadius = std::max(2, (int)roundf(TRUNCATION * sigma));
34  int mask_width = (2 * m_maskRadius) + 1;
35 
36  /* Compute Gaussian mask. */
37  m_mask = new double[mask_width];
38  double val = 1.0; /* Initialize center of Gaussian mask (rr=0 => exp(0)). */
39  m_mask[m_maskRadius] = val;
40  double sum = val;
41  for (int rr = 1; rr <= m_maskRadius; rr++)
42  {
43  val = exp(-(rr * rr) / TWO_SIGMA2); // Gaussian weight(rr,sigma)
44  m_mask[m_maskRadius + rr] = val;
45  m_mask[m_maskRadius - rr] = val;
46  sum += 2 * val;
47  }
48  for (int ii = 0; ii < mask_width; ii++)
49  m_mask[ii] /= sum; /* normalize to [0,1] */
50 }
51 
53 {
54  av_freep(reinterpret_cast<void*>(&m_edges.data[0]));
55  av_freep(reinterpret_cast<void*>(&m_convolved.data[0]));
56  av_freep(reinterpret_cast<void*>(&m_s2.data[0]));
57  av_freep(reinterpret_cast<void*>(&m_s1.data[0]));
58  delete []m_sgmSorted;
59  delete []m_sgm;
60  delete []m_mask;
61 }
62 
63 int
64 CannyEdgeDetector::resetBuffers(int newwidth, int newheight)
65 {
66  if (m_ewidth == newwidth && m_eheight == newheight)
67  return 0;
68 
69  if (m_sgm) {
70  /*
71  * Sentinel value to determine whether or not stuff has already been
72  * allocated.
73  */
74  av_freep(reinterpret_cast<void*>(&m_s1.data[0]));
75  av_freep(reinterpret_cast<void*>(&m_s2.data[0]));
76  av_freep(reinterpret_cast<void*>(&m_convolved.data[0]));
77  av_freep(reinterpret_cast<void*>(&m_edges.data[0]));
78  delete []m_sgm;
79  delete []m_sgmSorted;
80  m_sgm = nullptr;
81  }
82 
83  const int padded_width = newwidth + (2 * m_maskRadius);
84  const int padded_height = newheight + (2 * m_maskRadius);
85 
86  if (av_image_alloc(m_s1.data, m_s1.linesize,
87  padded_width, padded_height, AV_PIX_FMT_GRAY8, IMAGE_ALIGN))
88  {
89  LOG(VB_COMMFLAG, LOG_ERR, "CannyEdgeDetector::resetBuffers "
90  "av_image_alloc s1 failed");
91  return -1;
92  }
93 
94  if (av_image_alloc(m_s2.data, m_s2.linesize,
95  padded_width, padded_height, AV_PIX_FMT_GRAY8, IMAGE_ALIGN))
96  {
97  LOG(VB_COMMFLAG, LOG_ERR, "CannyEdgeDetector::resetBuffers "
98  "av_image_alloc s2 failed");
99  goto free_s1;
100  }
101 
102  if (av_image_alloc(m_convolved.data, m_convolved.linesize,
103  padded_width, padded_height, AV_PIX_FMT_GRAY8, IMAGE_ALIGN))
104  {
105  LOG(VB_COMMFLAG, LOG_ERR, "CannyEdgeDetector::resetBuffers "
106  "av_image_alloc convolved failed");
107  goto free_s2;
108  }
109 
110  if (av_image_alloc(m_edges.data, m_edges.linesize,
111  newwidth, newheight, AV_PIX_FMT_GRAY8, IMAGE_ALIGN))
112  {
113  LOG(VB_COMMFLAG, LOG_ERR, "CannyEdgeDetector::resetBuffers "
114  "av_image_alloc edges failed");
115  goto free_convolved;
116  }
117 
118  m_sgm = new unsigned int[1_UZ * padded_width * padded_height];
119  m_sgmSorted = new unsigned int[1_UZ * newwidth * newheight];
120 
121  m_ewidth = newwidth;
122  m_eheight = newheight;
123 
124  return 0;
125 
126 free_convolved:
127  av_freep(reinterpret_cast<void*>(&m_convolved.data[0]));
128 free_s2:
129  av_freep(reinterpret_cast<void*>(&m_s2.data[0]));
130 free_s1:
131  av_freep(reinterpret_cast<void*>(&m_s1.data[0]));
132  return -1;
133 }
134 
135 int
136 CannyEdgeDetector::setExcludeArea(int row, int col, int width, int height)
137 {
138  m_exclude.row = row;
139  m_exclude.col = col;
140  m_exclude.width = width;
141  m_exclude.height = height;
142  return 0;
143 }
144 
145 const AVFrame *
146 CannyEdgeDetector::detectEdges(const AVFrame *pgm, int pgmheight,
147  int percentile)
148 {
149  /*
150  * Canny edge detection
151  *
152  * See
153  * http://www.cs.cornell.edu/courses/CS664/2003fa/handouts/664-l6-edges-03.pdf
154  */
155 
156  const int pgmwidth = pgm->linesize[0];
157  const int padded_height = pgmheight + (2 * m_maskRadius);
158 
159  if (resetBuffers(pgmwidth, pgmheight))
160  return nullptr;
161 
162  if (pgm_convolve_radial(&m_convolved, &m_s1, &m_s2, pgm, pgmheight,
163  m_mask, m_maskRadius))
164  return nullptr;
165 
166  if (edge_mark_uniform_exclude(&m_edges, pgmheight, m_maskRadius,
167  sgm_init_exclude(m_sgm, &m_convolved, padded_height,
168  m_exclude.row + m_maskRadius, m_exclude.col + m_maskRadius,
169  m_exclude.width, m_exclude.height),
170  m_sgmSorted, percentile,
171  m_exclude.row, m_exclude.col, m_exclude.width, m_exclude.height))
172  return nullptr;
173 
174  return &m_edges;
175 }
176 
177 /* vim: set expandtab tabstop=4 shiftwidth=4: */
edgeDetector::edge_mark_uniform_exclude
int edge_mark_uniform_exclude(AVFrame *dst, int dstheight, int extramargin, const unsigned int *sgm, unsigned int *sgmsorted, int percentile, int excluderow, int excludecol, int excludewidth, int excludeheight)
Definition: EdgeDetector.cpp:186
edgeDetector::sgm_init_exclude
unsigned int * sgm_init_exclude(unsigned int *sgm, const AVFrame *src, int srcheight, int excluderow, int excludecol, int excludewidth, int excludeheight)
Definition: EdgeDetector.cpp:25
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
mythplayer.h
mythframe.h
AVFrame
struct AVFrame AVFrame
Definition: BorderDetector.h:15
CannyEdgeDetector::CannyEdgeDetector
CannyEdgeDetector(void)
Definition: CannyEdgeDetector.cpp:20
pgm_convolve_radial
int pgm_convolve_radial(AVFrame *dst, AVFrame *s1, AVFrame *s2, const AVFrame *src, int srcheight, const double *mask, int mask_radius)
Definition: pgm.cpp:224
mythlogging.h
pgm.h
CannyEdgeDetector.h
sizetliteral.h
edgeDetector
Definition: EdgeDetector.cpp:20
CannyEdgeDetector::resetBuffers
int resetBuffers(int newwidth, int newheight)
Definition: CannyEdgeDetector.cpp:64
CannyEdgeDetector::detectEdges
const AVFrame * detectEdges(const AVFrame *pgm, int pgmheight, int percentile) override
Definition: CannyEdgeDetector.cpp:146
CannyEdgeDetector::setExcludeArea
int setExcludeArea(int row, int col, int width, int height) override
Definition: CannyEdgeDetector.cpp:136
CannyEdgeDetector::~CannyEdgeDetector
~CannyEdgeDetector(void) override
Definition: CannyEdgeDetector.cpp:52