Basic Image AlgorithmS Library  2.8.0
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
Dilation.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 
26 #include "Dilation.hh"
27 #include "Base/Image/ImageConvert.hh"
28 #include <Base/Common/BIASpragma.hh>
29 
30 #include <limits>
31 
32 using namespace BIAS;
33 using namespace std;
34 
35 template <class InputStorageType, class OutputStorageType>
38 {
39  DilateLower_ = true;
40 }
41 
42 template <class InputStorageType, class OutputStorageType>
45  Image<OutputStorageType>& Destination,
46  int KernelSize)
47 {
48  if (Destination.IsEmpty())
49  Destination.Init(Source.GetWidth(), Source.GetHeight(),
50  Source.GetChannelCount());
51 #ifdef BIAS_BOUNDS_CHECK
52  if (Source.GetChannelCount() !=1)
53  BIASERR("Dilation::Dilate() only implemented for grey images");
54  if (! Source.SamePixelAndChannelCount(Destination))
55  BIASERR("Dilation::Dilate() wrong images izes");
56  if (KernelSize % 2 != 1)
57  BIASERR("Dilation::Dilate() odd KernelSize required");
58 #endif
59 
60  int Width = Source.GetWidth();
61  int Height = Source.GetHeight();
62  register int HalfKernelSize = (KernelSize - 1) / 2;
63  OutputStorageType *Dest = NULL;
64  register OutputStorageType **DestArray;
65  register const InputStorageType **SourceArray = Source.GetImageDataArray();
66  // if used in place temporary data is necessairy
67  if ((void*)Source.GetImageData() == (void*)Destination.GetImageData()){
68  Dest = new OutputStorageType[Height * Width];
69  DestArray = new OutputStorageType*[Height];
70  DestArray[0] = Dest;
71  for (register int i=1; i< Height; i++) {
72  DestArray[i] = DestArray[i-1] + Width;
73  }
74  } else {
75  DestArray = Destination.GetImageDataArray();
76  }
77  // loop
78  for (register int y = HalfKernelSize;
79  y < ((int)Source.GetHeight() - HalfKernelSize); y++){
80  for (register int x = HalfKernelSize;
81  x < ((int)Source.GetWidth() - HalfKernelSize); x++) {
82  DestArray[y][x] = 0;
83  for (register int ky = -HalfKernelSize; ky <= HalfKernelSize; ky++)
84  for (register int kx = -HalfKernelSize; kx <= HalfKernelSize; kx++)
85  if (DilateLower_) {
86  if (SourceArray[y+ky][x+kx]>DestArray[y][x])
87  DestArray[y][x]=SourceArray[y+ky][x+kx];
88  } else {
89  if ((DestArray[y][x]==0 && SourceArray[y+ky][x+kx]>0) ||
90  (SourceArray[y+ky][x+kx]<DestArray[y][x] && SourceArray[y+ky][x+kx]>0))
91  DestArray[y][x]=SourceArray[y+ky][x+kx];
92  }
93  }
94  }
95 
96  if ((void*)Source.GetImageData() == (void*)Destination.GetImageData()){
97  delete[] DestArray;
98  Destination.Release();
99  Destination.RedirectImageDataPointer(Dest);
100  }
101  // fill borders with zero
102  this->FillBorderConst(Destination, (unsigned short int)HalfKernelSize,
103  (unsigned short int)HalfKernelSize, (OutputStorageType)0);
104  return 0;
105 }
106 
107 template <class InputStorageType, class OutputStorageType>
110  const Image<InputStorageType>& orig,
112  bool Neighbor4) {
113 #ifdef BIAS_DEBUG
114  if ((src.GetChannelCount() !=1) || (dest.GetChannelCount() !=1) ||
115  (orig.GetChannelCount() !=1 ) ) {
116  BIASERR("Dilation::Dilate3Fast() only implemented for grey images");
117  return -1;
118  }
119  if (src.GetPixelCount()<25) {
120  BIASERR("Dilation::Dilate3Fast(): src has less than 25 pixel");
121  return -2;
122  }
123  if ( (src.GetHeight()<5) || (src.GetWidth() < 5)) {
124  BIASERR("Dilation::Dilate3Fast(): src has less than 5 cols or rows");
125  return -3;
126  }
127  if (src.GetPixelCount() != dest.GetPixelCount()) {
128  BIASERR("Dilation::Dilate3Fast(): src and dest have different sizes");
129  return -3;
130  }
131 #endif
132  if (orig.GetStorageType()==dest.GetStorageType()) {
133  // copy orig to dest
134  memcpy(dest.GetImageData() , orig.GetImageData(),
135  orig.GetPixelCount()*sizeof(InputStorageType));
136  } else {
137  // have to convert
138  ImageConvert::ConvertST(orig, dest, dest.GetStorageType());
139  }
140  // then delete the eroded background form src in dest
141  register OutputStorageType *d=dest.GetImageDataArray()[1]+1;
142  register const InputStorageType *p1=src.GetImageDataArray()[0];
143  register const InputStorageType *p2=p1+1, *p3 = p2+1;
144  register const InputStorageType *p4=src.GetImageDataArray()[1];
145  register const InputStorageType *p5 = p4+1, *p6=p5+1;
146  register const InputStorageType *p7 =src.GetImageDataArray()[2];
147  register const InputStorageType *p8 = p7+1, *p9=p8+1;
148  register const InputStorageType *last=&(src.GetImageData()[src.GetPixelCount()-1]);
149  if (Neighbor4) {
150  while (p8<last) {
151  if (*p5==0)
152  if (*p2==0)
153  if (*p4==0)
154  if (*p6==0)
155  if (*p8==0)
156  *d=0;
157  p2++; p4++; p5++; p6++; p8++; d++;
158  }
159  } else {
160  while (p9<=last) {
161  if (*p5 == 0)
162  if (*p1==0)
163  if (*p2==0)
164  if (*p3==0)
165  if (*p4==0)
166  if (*p6==0)
167  if (*p7==0)
168  if (*p8==0)
169  if (*p9==0)
170  *d=0;
171  p1++; p2++; p3++; p4++; p5++; p6++; p7++; p8++; p9++; d++;
172  }
173  }
174  //// set border to zero
175  // top and bottom
176  register OutputStorageType *o1,*o2,*o9,*olast;
177  o1 = dest.GetImageDataArray()[0];
178  o9 = dest.GetImageDataArray()[dest.GetHeight()-1];
179  olast=&(dest.GetImageData()[dest.GetPixelCount()-1]);
180  while (o9<=olast) {
181  *o1=0; *o9=0;
182  o1++; o9++;
183  }
184  // left and right
185  register unsigned int offset = dest.GetWidth();
186  o1 = dest.GetImageData();
187  o2 = o1+offset-1;
188  while (o2<=olast) {
189  *o1 = 0;
190  *o2 = 0;
191  o1 += offset;
192  o2 += offset;
193  }
194  return 0;
195 }
196 
197 template <class InputStorageType, class OutputStorageType>
201  bool Neighbor4) {
202 #ifdef BIAS_DEBUG
203  if ((src.GetChannelCount() !=1) || (dest.GetChannelCount() !=1) ) {
204  BIASERR("Dilation::Dilate3Fast() only implemented for grey images");
205  return -1;
206  }
207  if (src.GetPixelCount()<25) {
208  BIASERR("Dilation::Dilate3Fast(): src has less than 25 pixel");
209  return -2;
210  }
211  if ( (src.GetHeight()<5) || (src.GetWidth() < 5)) {
212  BIASERR("Dilation::Dilate3Fast(): src has less than 5 cols or rows");
213  return -3;
214  }
215  if (src.GetPixelCount() != dest.GetPixelCount()) {
216  BIASERR("Dilation::Dilate3Fast(): src and dest have different sizes");
217  return -3;
218  }
219 #endif
220 
221  // then delete the eroded background form src in dest
222  register OutputStorageType *d=dest.GetImageDataArray()[1]+1;
223  register const InputStorageType *p1=src.GetImageDataArray()[0];
224  register const InputStorageType *p2=p1+1, *p3 = p2+1;
225  register const InputStorageType *p4=src.GetImageDataArray()[1];
226  register const InputStorageType *p5 = p4+1, *p6=p5+1;
227  register const InputStorageType *p7 =src.GetImageDataArray()[2];
228  register const InputStorageType *p8 = p7+1, *p9=p8+1;
229  register const InputStorageType *last=&(src.GetImageData()[src.GetPixelCount()-1]);
230  if (Neighbor4) {
231  while (p8<last) {
232  *d = OutputStorageType(255);
233  if (*p2==0)
234  if (*p4==0)
235  if (*p5==0)
236  if (*p6==0)
237  if (*p8==0)
238  *d = 0;
239  p2++; p4++; p5++; p6++; p8++; d++;
240  }
241  } else {
242  while (p9<=last) {
243  *d = OutputStorageType(255);
244  if (*p1==0)
245  if (*p2==0)
246  if (*p3==0)
247  if (*p4==0)
248  if (*p5==0)
249  if (*p6==0)
250  if (*p7==0)
251  if (*p8==0)
252  if (*p9==0)
253  *d=0;
254  p1++; p2++; p3++; p4++; p5++; p6++; p7++; p8++; p9++; d++;
255  }
256  }
257  //// set border to zero
258  // top and bottom
259  register OutputStorageType *o1,*o2,*o9,*olast;
260  o1 = dest.GetImageDataArray()[0];
261  o9 = dest.GetImageDataArray()[dest.GetHeight()-1];
262  olast=&(dest.GetImageData()[dest.GetPixelCount()-1]);
263  while (o9<=olast) {
264  *o1=0; *o9=0;
265  o1++; o9++;
266  }
267  // left and right
268  register unsigned int offset = dest.GetWidth();
269  o1 = dest.GetImageData();
270  o2 = o1+offset-1;
271  while (o2<=olast) {
272  *o1 = 0;
273  *o2 = 0;
274  o1 += offset;
275  o2 += offset;
276  }
277  return 0;
278 }
279 
280 template <class InputStorageType, class OutputStorageType>
284  if (src.GetChannelCount()!=1) {
285  BIASERR("Erosion only for 1 channel images");
286  return -1;
287  }
288  if (_FilterBorderHandling==TBH_valid) {
289  if (kernelSize_==3) {
290  Image<InputStorageType> tmp(src);
291  if ( (dst.IsEmpty()) || (! src.SamePixelAndChannelCount(dst)) )
292  dst=src;
293 
294  tmp.FillImageWithConstValue( InputStorageType(255) );
295 
296  Dilate3Fast(src,tmp,dst,false);
297  dst.GetROI()->SetCorners(1,1,dst.GetWidth()-2,dst.GetHeight()-2);
298  } else {
299  Dilate(src,dst,kernelSize_);
300  dst.GetROI()->SetCorners(1,1,dst.GetWidth()-2,dst.GetHeight()-2);
301  }
302  } else if (_FilterBorderHandling==TBH_same) {
304  tmp.Init(src.GetWidth() + (kernelSize_/2)*2,
305  src.GetHeight()+ (kernelSize_/2)*2, 1);
306  tmp.GetROI()->SetCorners(kernelSize_/2 ,kernelSize_/2 ,
307  tmp.GetWidth()-(kernelSize_/2),
308  tmp.GetHeight()-(kernelSize_/2));
309  tmp.Paste2ROI(src);
310  Dilate(tmp,dst,kernelSize_);
311  dst.GetROI()->SetCorners(kernelSize_/2 ,kernelSize_/2 ,
312  tmp.GetWidth() -(kernelSize_/2),
313  tmp.GetHeight()-(kernelSize_/2));
314  dst.Cut2ROI();
315  } else {
316  BIASERR("Unknown border handling.");
317  return -1;
318  }
319 
320  return 0;
321 }
322 
323 template <class InputStorageType, class OutputStorageType>
325 GetBordersValid_(int& border_x, int& border_y) const
326 {
327  BIASERR("no parameter support");
328  BIASABORT;
329 }
330 
331 //////////////////////////////////////////////////////////////////////////
332 // instantiation
333 //////////////////////////////////////////////////////////////////////////
334 namespace BIAS{
335 #define FILTER_INSTANTIATION_CLASS Dilation
336 #include "Filterinst.hh"
337 }
void Release()
reimplemented from ImageBase
Definition: Image.cpp:1579
int Cut2ROI()
reduces image to current ROI, !!! image size changes !!!
Definition: ImageBase.cpp:646
int SetCorners(unsigned UpperLeftX, unsigned UpperLeftY, unsigned LowerRightX, unsigned LowerRightY)
Sets a rectangular region of interest.
Definition: ROI.cpp:287
bool IsEmpty() const
check if ImageData_ points to allocated image buffer or not
Definition: ImageBase.hh:245
Dilation operator for binary images (black and white)
Definition: Dilation.hh:43
int Dilate3Fast(const Image< InputStorageType > &src, const Image< InputStorageType > &orig, Image< OutputStorageType > &dest, bool Neighbor4=false)
Very fast dilate with 3x3 mask, all values, which are not not zero, are treated as foreground...
Definition: Dilation.cpp:109
unsigned int GetWidth() const
Definition: ImageBase.hh:312
virtual int Filter(const Image< InputStorageType > &src, Image< OutputStorageType > &dst)
Does the dilation.
Definition: Dilation.cpp:282
ROI * GetROI()
Returns a pointer to the roi object.
Definition: ImageBase.hh:615
static int ConvertST(const BIAS::ImageBase &source, BIAS::ImageBase &dest, ImageBase::EStorageType targetST)
Function to convert the storage type of images e.g.
unsigned int GetChannelCount() const
returns the number of Color channels, e.g.
Definition: ImageBase.hh:382
int Dilate(const Image< InputStorageType > &Source, Image< OutputStorageType > &Destination, int KernelSize=3)
dilate with square kernel filled with 255
Definition: Dilation.cpp:44
unsigned int GetHeight() const
Definition: ImageBase.hh:319
void FillImageWithConstValue(StorageType Value)
fill grey images
Definition: Image.cpp:456
bool SamePixelAndChannelCount(const ImageBase &Image) const
checks if data area has same &quot;size&quot; as Image of other type
Definition: ImageBase.hh:73
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
Definition: Dilation.cpp:325
enum EStorageType GetStorageType() const
Definition: ImageBase.hh:414
int Paste2ROI(const ImageBase &Image)
paste Image to current ROI
Definition: ImageBase.cpp:603
unsigned long int GetPixelCount() const
returns number of pixels in image
Definition: ImageBase.hh:422
void RedirectImageDataPointer(void *data)
This method takes data and set the internal image data pointer to this.
Definition: ImageBase.hh:859
const StorageType ** GetImageDataArray() const
overloaded GetImageDataArray() from ImageBase
Definition: Image.hh:153