Basic Image AlgorithmS Library  2.8.0
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
CannyEdge.cpp
1 /*
2  This file is part of the BIAS library (Basic ImageAlgorithmS).
3 
4  Copyright (C) 2003-2009 (see file CONTACT for details)
5  Multimediale Systeme der Informationsverarbeitung
6  Institut fuer Informatik
7  Christian-Albrechts-Universitaet Kiel
8 
9 
10  BIAS is free software; you can redistribute it and/or modify
11  it under the terms of the GNU Lesser General Public License as published by
12  the Free Software Foundation; either version 2.1 of the License, or
13  (at your option) any later version.
14 
15  BIAS is distributed in the hope that it will be useful,
16  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  GNU Lesser General Public License for more details.
19 
20  You should have received a copy of the GNU Lesser General Public License
21  along with BIAS; if not, write to the Free Software
22  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23  */
24 
25 #include "Rescale.hh"
26 #include "CannyEdge.hh"
27 
28 namespace BIAS {
29 
30  template<class InputStorageType, class OutputStorageType>
32  gsigma_ = 1.4f;
33  edgeWidth_ = 1;
34  useAbsThresholds_ = false;
35  thresLow_ = 60;
36  thresHigh_ = 10;
37  Vector<FM_FLOAT> h(5), v(1);
38  h[0] = 0.5f;
39  h[1] = 1.0f;
40  h[2] = 0.0f;
41  h[3] = -1.0f;
42  h[4] = -0.5f;
43  v[0] = 1.0f;
44 
45  FilterMask f(h, v);
46  ConvX_.SetKernel(f);
47 
48  FilterMask g(v, h);
49  ConvY_.SetKernel(g);
50 
51  }
52 
53  template<class InputStorageType, class OutputStorageType>
55  }
56 
57  template<class InputStorageType, class OutputStorageType>
62 
63  w_ = src.GetWidth();
64  h_ = src.GetHeight();
65  BIASASSERT(src.GetChannelCount() == 1);
66  if (!gx.IsEmpty())
67  gx.Release();
68  if (!gy.IsEmpty())
69  gy.Release();
70  if (!gdir.IsEmpty())
71  gdir.Release();
72  if (!magnitude.IsEmpty())
73  magnitude.Release();
74  if (!dst.IsEmpty())
75  dst.Release();
76  gx.Init(w_,h_,1);
77  gy.Init(w_,h_,1);
78  magnitude.Init(w_,h_,1);
79  gdir.Init(w_,h_,1);
80  dst.Init(w_,h_,1);
81 
82  Image<OutputStorageType> smoothed;
83  SmoothImage_(src, smoothed);
84 
85  CalculateGradients_(smoothed, gx, gy, magnitude, gdir, dst);
86 
87  return 0;
88  }
89 
90  template<class InputStorageType, class OutputStorageType>
92  const Image<InputStorageType>& src, Image<OutputStorageType>& smoothed) {
93 
96  scaler.SetFactor(0.5f);
97  scaler.Filter(src, tmp);
98  gauss_.SetSigma(gsigma_);
99  gauss_.Filter(tmp, smoothed);
100  return 0;
101  }
102 
103  template<class InputStorageType, class OutputStorageType>
105  Image<OutputStorageType> intermediaries[4];
106  int res = Filter(src,
107  intermediaries[0],
108  intermediaries[1],
109  intermediaries[2],
110  intermediaries[3], dst);
111  return res;
112  }
113 
114  template<class InputStorageType, class OutputStorageType>
119 
120  Image<OutputStorageType> tmpx, tmpy;
121  tmpx.Init(w_*2, h_*2, 1);
122  tmpy.Init(w_*2, h_*2, 1);
123  ConvX_.Filter(src, tmpx);
124  ConvY_.Filter(src, tmpy);
125 
126  // calculate magnitude and directions.
127  OutputStorageType **idaTX = tmpx.GetImageDataArray();
128  OutputStorageType **idaTY = tmpy.GetImageDataArray();
129  OutputStorageType **idaX = gx.GetImageDataArray();
130  OutputStorageType **idaY = gy.GetImageDataArray();
131  OutputStorageType **idaM = magnitude.GetImageDataArray();
132  OutputStorageType **idaD = gdir.GetImageDataArray();
133  OutputStorageType **idaR = dst.GetImageDataArray();
134 
135  for (unsigned int y=0;y<h_*2;y+=2) {
136  for (unsigned int x=0;x<w_*2;x+=2) {
137  idaY[y/2][x/2] = idaTY[y][x];
138  idaX[y/2][x/2] = idaTX[y][x];
139  }
140  }
141 
142  for (unsigned int y=0;y<h_;y++) {
143  for (unsigned int x=0;x<w_;x++) {
144  idaM[y][x] = (OutputStorageType)(abs((double)(idaY[y][x]))+abs((double)(idaX[y][x])));
145  }
146  }
147 
148  for (unsigned int y=0;y<h_;y++) {
149  for (unsigned int x=0;x<w_;x++) {
150  if (idaX[y][x] == 0) {
151  if (idaY[y][x] == 0) {
152  idaD[y][x] = 0;
153  } else {
154  if (idaY[y][x] < 0) {
155  idaY[y][x] = -idaY[y][x];
156  }
157  idaD[y][x] = 90;
158  }
159  } else if(idaX[y][x]<0 && idaY[y][x]>0) {
160  idaD[y][x] = (OutputStorageType)(180 - ((atan((double)(idaY[y][x])/(double)( -idaX[y][x]))) * (180/M_PI)));
161  } else if(idaX[y][x]>0 && idaY[y][x]<0) {
162  idaD[y][x] = (OutputStorageType)(180 - ((atan((double)( -idaY[y][x])/(double)(idaX[y][x]))) * (180/M_PI)));
163  } else {
164  idaD[y][x] = (OutputStorageType)((atan((double)(idaY[y][x])/(double)(idaX[y][x]))) * (180/M_PI));
165  }
166  if(idaD[y][x] < 22.5)
167  idaD[y][x] = 0;
168  else if(idaD[y][x] < 67.5)
169  idaD[y][x] = 45;
170  else if(idaD[y][x] < 112.5)
171  idaD[y][x] = 90;
172  else if(idaD[y][x] < 157.5)
173  idaD[y][x] = 135;
174  else
175  idaD[y][x] = 0;
176  }
177  }
178 
179  OutputStorageType highThreshold = thresHighAbs_;
180  OutputStorageType lowThreshold = thresLowAbs_;
181  if (!useAbsThresholds_) {
182  DetermineThresholds_(magnitude, lowThreshold, highThreshold);
183  BIASCDOUT(D_FILTERBASE_CALLSTACK, "CannyEdge determined thresholds: " << lowThreshold << " " << highThreshold);
184  if (lowThreshold == highThreshold) {
185  lowThreshold = 60;
186  highThreshold = 10;
187  BIASWARN("CannyEdge could not determine thresholds automatically, resetting to: " << lowThreshold << " " << highThreshold);
188  }
189  }
190 
191  for (unsigned int y=edgeWidth_;y<h_-edgeWidth_;y++) {
192  for (unsigned int x=edgeWidth_;x<w_-edgeWidth_;x++) {
193  OutputStorageType leftNeighbor;
194  OutputStorageType rightNeighbor;
195  if(idaD[y][x] == 0) {
196  leftNeighbor = idaM[y][x-edgeWidth_];
197  rightNeighbor = idaM[y][x+edgeWidth_];
198  } else if(idaD[y][x] == 45) {
199  leftNeighbor = idaM[y+edgeWidth_][x-edgeWidth_];
200  rightNeighbor = idaM[y-edgeWidth_][x+edgeWidth_];
201  } else if(idaD[y][x] == 90) {
202  leftNeighbor = idaM[y-edgeWidth_][x];
203  rightNeighbor = idaM[y+edgeWidth_][x];
204  } else {
205  leftNeighbor = idaM[y-edgeWidth_][x-edgeWidth_];
206  rightNeighbor = idaM[y+edgeWidth_][x+edgeWidth_];
207  }
208  if (idaM[y][x] < leftNeighbor || idaM[y][x] < rightNeighbor) {
209  idaR[y][x] = 0;
210  } else {
211  if(idaM[y][x] >= highThreshold) {
212  idaR[y][x] = 255;
213  } else if(idaM[y][x] < lowThreshold) {
214  idaR[y][x] = 0;
215  } else {
216  idaR[y][x] = 0;
217  for (unsigned int yw=y-1;yw<=y+1;yw++) {
218  for (unsigned int xw=x-1;xw<=x+1;xw++) {
219  if (idaR[yw][xw]>=highThreshold) {
220  idaR[y][x] = 255;
221  break;
222  }
223  }
224  }
225  }
226  }
227  }
228  }
229 
230  return 0;
231  }
232 
233  template <class InputStorageType, class OutputStorageType>
234  void CannyEdge<InputStorageType, OutputStorageType>::GetBordersValid_(int& border_x, int& border_y) const {
235  BIASERR("no parameter support");
236  BIASABORT;
237  }
238 
239  template<class InputStorageType, class OutputStorageType>
240  int CannyEdge<InputStorageType, OutputStorageType>::DetermineThresholds_(const Image<OutputStorageType> &src, OutputStorageType &low, OutputStorageType &high)
241  {
242  const OutputStorageType *ida = src.GetImageData();
243  OutputStorageType min, max;
244  src.GetMinMaxPixelValue(min, max);
245  if (max==0 || max==min) {
246  BIASERR("can not determine thresholds");
247  BIASABORT;
248  }
249  unsigned int histo[256];
250  unsigned int idx = 0;
251  for (;idx<256;idx++) {
252  histo[idx]=0;
253  }
254  unsigned int allPixelCount = src.GetPixelCount();
255  unsigned int upperPercent = allPixelCount * thresHigh_ / 100;
256  unsigned int lowerPercent = allPixelCount * thresLow_ / 100;
257  for (unsigned int i=0;i<allPixelCount;i++) {
258  idx = (unsigned int)((float)(ida[i] - min) / (float)(max-min) * 255.0f);
259  histo[idx] ++;
260  }
261  idx = 255;
262  while (histo[idx] <= upperPercent) {
263  upperPercent -= histo[idx];
264  idx--;
265  }
266  high = (OutputStorageType)((float)idx / 255.0f * (max-min) + min);
267  idx = 0;
268  while (histo[idx] <= lowerPercent) {
269  lowerPercent -= histo[idx];
270  idx++;
271  }
272  low = (OutputStorageType)((float)idx / 255.0f * (max-min) + min);
273  return 0;
274  }
275 
276  template<class InputStorageType, class OutputStorageType>
278  {
279  gsigma_=sigma;
280  return 0;
281  }
282 
283  template<class InputStorageType, class OutputStorageType>
284  int CannyEdge<InputStorageType, OutputStorageType>::SetThresholdsAbsolute(OutputStorageType lowAbs_, OutputStorageType highAbs_)
285  {
286  useAbsThresholds_ = true;
287  thresLowAbs_ = lowAbs_;
288  thresHighAbs_ = highAbs_;
289  return 0;
290  }
291 
292  template<class InputStorageType, class OutputStorageType>
294  {
295  useAbsThresholds_ = false;
296  thresLow_ = low_;
297  thresHigh_ = high_;
298  return 0;
299  }
300 
301  template<class InputStorageType, class OutputStorageType>
303  {
304  edgeWidth_ = edgeWidth;
305  return 0;
306  }
307 
308 
309 //////////////////////////////////////////////////////////////////////////
310 // instantiation
311 //////////////////////////////////////////////////////////////////////////
312 
313 #define FILTER_INSTANTIATION_CLASS CannyEdge
314 #define FILTER_INSTANTIATION_NO_UNSIGNED_OUTPUT
315 
316 // small range data types not supported at this time
317 #ifdef BUILD_IMAGE_CHAR
318 #define CANNYUNDEF_CHAR
319 #undef BUILD_IMAGE_CHAR
320 #endif
321 
322 #ifdef BUILD_IMAGE_USHORT
323 #undef BUILD_IMAGE_USHORT
324 #define CANNYUNDEF_USHORT
325 #endif
326 
327 #include "Filterinst.hh"
328 
329 #ifdef CANNYUNDEF_CHAR
330 #define BUILD_IMAGE_CHAR
331 #undef CANNYUNDEF_CHAR
332 #endif
333 
334 #ifdef CANNYUNDEF_USHORT
335 #define BUILD_IMAGE_USHORT
336 #undef CANNYUNDEF_USHORT
337 #endif
338 
339 #undef FILTER_INSTANTIATION_NO_UNSIGNED_OUTPUT
340 #undef FILTER_INSTANTIATION_CLASS
341 
342 } // namespace BIAS
void Release()
reimplemented from ImageBase
Definition: Image.cpp:1579
CannyEdge()
Constructor, setting default values.
Definition: CannyEdge.cpp:31
int SmoothImage_(const Image< InputStorageType > &src, Image< OutputStorageType > &smoothed)
Definition: CannyEdge.cpp:91
int DetermineThresholds_(const Image< OutputStorageType > &src, OutputStorageType &low, OutputStorageType &high)
Definition: CannyEdge.cpp:240
bool IsEmpty() const
check if ImageData_ points to allocated image buffer or not
Definition: ImageBase.hh:245
int CalculateGradients_(const Image< OutputStorageType > &src, Image< OutputStorageType > &gx, Image< OutputStorageType > &gy, Image< OutputStorageType > &magnitude, Image< OutputStorageType > &gdir, Image< OutputStorageType > &dst)
Definition: CannyEdge.cpp:115
Down-, Upsampling routines and Resize.
Definition: Rescale.hh:71
void GetMinMaxPixelValue(StorageType &min, StorageType &max, unsigned short int channel=0, unsigned int *mincoo=NULL, unsigned int *maxcoo=NULL) const
returns the minimal and maximal pixel value in channel only Finds minimum and maximum pixel value in ...
Definition: Image.cpp:802
unsigned int GetWidth() const
Definition: ImageBase.hh:312
int SetThresholdsAbsolute(OutputStorageType lowAbs_, OutputStorageType highAbs_)
set absolute value of low and high thresholds for hysteresis in magnitude gradient image ...
Definition: CannyEdge.cpp:284
unsigned int GetChannelCount() const
returns the number of Color channels, e.g.
Definition: ImageBase.hh:382
virtual int Filter(const Image< InputStorageType > &src, Image< OutputStorageType > &dst)
scales the src to dst using the downsampling factor from SetFactor()
Definition: Rescale.cpp:89
int SetThresholdsRelative(unsigned int low_, unsigned int high_)
set value of low and high thresholds for hysteresis in magnitude gradient image in terms of percent o...
Definition: CannyEdge.cpp:293
unsigned int GetHeight() const
Definition: ImageBase.hh:319
int SetGaussSigma(float sigma)
before edge detection, the input image is blurred with a gaussian. Set sigma here (defaults to 1...
Definition: CannyEdge.cpp:277
void Init(unsigned int Width, unsigned int Height, unsigned int channels=1, enum EStorageType storageType=ST_unsignedchar, const bool interleaved=true)
calls Init from ImageBase storageType is ignored, just dummy argument
Definition: Image.cpp:421
const StorageType * GetImageData() const
overloaded GetImageData() from ImageBase
Definition: Image.hh:137
virtual void GetBordersValid_(int &border_x, int &border_y) const
not implemented
Definition: CannyEdge.cpp:234
int SetEdgeWidth(unsigned int edgeWidth)
set edge width for hysteresis.
Definition: CannyEdge.cpp:302
unsigned long int GetPixelCount() const
returns number of pixels in image
Definition: ImageBase.hh:422
A filter mask (or a kernel) used for convolution.
Definition: FilterMask.hh:61
virtual ~CannyEdge()
Definition: CannyEdge.cpp:54
void SetFactor(double factor)
the downsampling factor
Definition: Rescale.hh:361
virtual int Filter(const Image< InputStorageType > &src, Image< OutputStorageType > &gx, Image< OutputStorageType > &gy, Image< OutputStorageType > &magnitude, Image< OutputStorageType > &gdir, Image< OutputStorageType > &dst)
call for getting all intermediary results
Definition: CannyEdge.cpp:58
const StorageType ** GetImageDataArray() const
overloaded GetImageDataArray() from ImageBase
Definition: Image.hh:153