Basic Image AlgorithmS Library  2.8.0
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
Label.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 #ifdef WIN32
26 # pragma warning (disable: 4251) // STL MAP DLL warning noise (JW)
27 #endif
28 
29 #include <limits.h>
30 #include <stdio.h>
31 #include "Label.hh"
32 
33 #include <Base/Image/ImageIO.hh>
34 #include <Base/Image/ImageConvert.hh>
35 
36 #include <algorithm>
37 
38 #include <Base/Common/BIASpragma.hh>
39 #include <MathAlgo/Median1D.hh>
40 
41 #define ERR_ILLT 0 /* Datenstruktur wird nicht unterstuetzt */
42 #define ERR_ILLI 1 /* Datentyp wird nicht unterstuetzt */
43 #define ERR_NOLB 0 /* Zu viele Gebiete */
44 
45 #define MAX_SEG UCHAR_MAX
46 #define MAX_LAB USHRT_MAX
47 
48 #define SEGDEF 1
49 
50 using namespace BIAS;
51 using namespace std;
52 
53 
54 
56 {
57  LabelInitialized_=false;
58  _FilterBorderHandling=TBH_same;
59  //AddDebugLevel(D_LABEL);
60 }
61 
63 {}
64 
65 
67 {
68  BIASDOUT(D_INIT,"LabelInit_()");
69  unsigned int UpperLeftX, UpperLeftY, LowerRightX, LowerRightY;
70  Image.GetROI()->GetCorners(UpperLeftX, UpperLeftY, LowerRightX, LowerRightY);
71  LabelSumImage_.Init(LowerRightX - UpperLeftX, LowerRightY - UpperLeftY);
72  LabelResultImage_.Init(LowerRightX - UpperLeftX,
73  LowerRightY - UpperLeftY);
74  LabelInitialized_=true;
75 }
76 /*
77 void Label::LabelInit_(const Image<float>& Image)
78 {
79  BIASDOUT(D_INIT,"LabelInit_()");
80  unsigned int UpperLeftX, UpperLeftY, LowerRightX, LowerRightY;
81  Image.GetROI()->GetCorners(UpperLeftX, UpperLeftY, LowerRightX, LowerRightY);
82  LabelSumImage_.Init(LowerRightX - UpperLeftX, LowerRightY - UpperLeftY);
83  LabelResultImage_.Init(LowerRightX - UpperLeftX,
84  LowerRightY - UpperLeftY);
85  LabelInitialized_=true;
86 }
87 
88 void Label::LabelInit_(const Image<unsigned char>& Image)
89 {
90  BIASDOUT(D_INIT,"LabelInit_()");
91  unsigned int UpperLeftX, UpperLeftY, LowerRightX, LowerRightY;
92  Image.GetROI()->GetCorners(UpperLeftX, UpperLeftY, LowerRightX, LowerRightY);
93  LabelSumImage_.Init(LowerRightX - UpperLeftX, LowerRightY - UpperLeftY);
94  LabelResultImage_.Init(LowerRightX - UpperLeftX,
95  LowerRightY - UpperLeftY);
96  LabelInitialized_=true;
97 }
98 */
99 
101 {
102  BIASDOUT(D_INIT,"LabelShortRelease_()");
103  LabelSumImage_.Release();
104  LabelResultImage_.Release();
105  LabelInitialized_=false;
106 }
107 
108 
109 
111 {
112  BIASCDOUT(D_FILTERBASE_CALLSTACK, "Label::Label4Neighbour_\n");
113  int nx, ny, i, k, no_seg, lab_seg2, lab_segv, no_all, *seg_list = NULL;
114  register int value, lab_seg1;
115  register LABEL_CALC_TYPE *adr, *adr_out;
116  // initialize
117  try { seg_list = new int[MAX_LAB]; }
118  catch (bad_alloc) { BIASERR("new failed "); }
119  nx = LabelSumImage_.GetWidth();
120  ny = LabelSumImage_.GetHeight();
121  adr = LabelSumImage_.GetImageData();
122  adr_out = LabelResultImage_.GetImageData();
123  no_seg = 0;
124 
125  /*****
126  *
127  * FIRST LINE
128  *
129  *****/
130  adr++;
131  *adr_out++ = 0;
132  seg_list[0] = SEGDEF;
133  lab_seg1 = 0;
134  for ( k = nx-1 ; k > 0 ; k--)
135  {
136  if (*adr != *(adr-1))
137  {
138  no_seg++;
139  seg_list[no_seg] = SEGDEF;
140  lab_seg1 = no_seg;
141  };
142  adr++;
143  *adr_out++ = lab_seg1;
144  };
145 
146  /*****
147  *
148  * NEXT LINES
149  *
150  *****/
151  for ( i = ny-1 ; i > 0 ; i--)
152  {
153 
154  /*****
155  *
156  * FIRST PIXEL
157  *
158  *****/
159  value = *adr;
160  lab_seg1 = -1;
161  if ( *(adr-nx) == value ) lab_seg1 = *(adr_out-nx);
162 
163  if ( lab_seg1 == -1 )
164  {
165  no_seg++;
166  seg_list[no_seg] = SEGDEF;
167  lab_seg1 = no_seg;
168  };
169  adr++;
170  adr_out++;
171 
172  /*****
173  *
174  * CHECK LABEL OF NEXT PIXELS
175  *
176  *****/
177  lab_segv = lab_seg1;
178  for ( k = nx-1 ; k > 0; k--)
179  {
180  lab_seg1 = -1;
181  lab_seg2 = *(adr_out-nx);
182  value = *adr;
183  if ( *(adr-1) == value)
184  {
185  lab_seg1 = lab_segv;
186  }
187  else if ( *(adr-nx) == value)
188  {
189  lab_seg1 = *(adr_out-nx);
190  };
191  /*****
192  *
193  * NEW REGION ?
194  *
195  *****/
196  if ( lab_seg1 == -1)
197  {
198  no_seg++;
199  seg_list[no_seg] = SEGDEF;
200  lab_seg1 = no_seg;
201  if (no_seg > MAX_LAB) {
202  BIASERR("error: too many blobs " << ERR_NOLB);
203  }
204  };
205 
206  /*****
207  *
208  * ACTUALIZE REGION LINE
209  *
210  *****/
211  *(adr_out-1) = lab_segv;
212  lab_segv = lab_seg1;
213 
214  /*****
215  *
216  * CHECK REGION MERGING
217  *
218  *****/
219  if ( k != 1 && value == *(adr-nx) && lab_seg1 != lab_seg2)
220  {
221  int m;
222  seg_list[lab_seg2] = -lab_seg1-1;
223  for ( m = nx ; m > 0; m--)
224  {
225  if ( *(adr_out-m) == lab_seg2)
226  *(adr_out-m) = lab_seg1;
227  };
228  lab_segv = lab_seg1;
229  };
230 
231  adr_out++;
232  adr++;
233  };
234  *(adr_out-1) = lab_segv;
235  };
236 
237  /*****
238  *
239  * GET NEW LABEL
240  *
241  *****/
242  no_all = 0;
243  for ( i = 0; i <= no_seg ; i++)
244  {
245  if (seg_list[i] == SEGDEF)
246  {
247  seg_list[i] = no_all;
248  no_all++;
249  };
250  };
251 
252  /*****
253  *
254  * LABEL MERGED REGIONS
255  *
256  *****/
257  for ( i = 0; i <= no_seg ; i++)
258  {
259  int ind;
260  ind = i;
261  while (seg_list[ind] < 0 )
262  {
263  ind = -seg_list[ind]-1;
264  };
265  seg_list[i] = seg_list[ind];
266  };
267 
268  /*****
269  *
270  * NEW IMAGE-LABEL
271  *
272  *****/
273  adr_out = LabelResultImage_.GetImageData();
274  for ( i = nx*ny ; i > 0 ; i--)
275  {
276  *adr_out = seg_list[*adr_out];
277  adr_out++;
278  };
279 
280  delete [] seg_list;
281  return (no_all);
282 }
283 
284 
285 
287  BIAS::Image<LABEL_CALC_TYPE>& DestinationImage)
288 {
289  BIASCDOUT(D_FILTERBASE_CALLSTACK, "Label::Label4Neighbour\n");
290  int CornerCount=0;
291  if (!LabelInitialized_){
292  LabelInit_(Image);
293  }
294  if ( ! Image.SamePixelAndChannelCount(LabelSumImage_) ){
295  LabelRelease_();
296  LabelInit_(Image);
297  }
298  Image.GetCopyOfROI(LabelSumImage_);
299 
300  CornerCount = Label4Neighbour_();
301 
302  DestinationImage.Paste2ROI(LabelResultImage_);
303 
304  return CornerCount;
305 }
306 
307 
309  Image<unsigned char>& DestinationImage)
310 {
311  BIASCDOUT(D_FILTERBASE_CALLSTACK, "Label::Label4Neighbour\n");
312  int CornerCount=0;
313 
314  if (!LabelInitialized_)
315  LabelInit_(image);
316 
317 
318  if ( ! image.SamePixelAndChannelCount(LabelSumImage_) ){
319  LabelRelease_();
320  LabelInit_(image);
321  }
322 
323  // explicit cast
325  image.GetCopyOfROI(roi);
326  ImageConvert::ConvertST(roi, LabelSumImage_, LABEL_STORAGE_TYPE);
327 
328  // ImageIO::Save("labelsumimage.",LabelSumImage_);
329 
330 
331  CornerCount = Label4Neighbour_();
332 
333  if (CornerCount > MAX_SEG){
334  BIASERR("Label::Label4Neighbour() Segmentzahl "
335  << CornerCount <<" der Label zu gross\n");
336  CornerCount = MAX_SEG;
337  }
338 
339  DestinationImage.Paste2ROI(LabelResultImage_);
340 
341  return CornerCount;
342 }
343 
345 {
346  BIASCDOUT(D_FILTERBASE_CALLSTACK, "Label::Process\n");
347  if (!LabelInitialized_)
348  LabelInit_(im);
349 
350  Image<unsigned char> roiImg;
351  im.GetCopyOfROI(roiImg);
352  unsigned minx, miny, maxx, maxy;
353  im.GetROI()->GetCorners(minx, miny, maxx, maxy);
354  /*static int coun=0;
355  ostringstream os("");
356  os << setw(4)<<setfill('0')<<coun;
357  ImageIO::Save("roi-"+os.str()+".mip", roiImg);*/
358  if (!LabelResultImage_.SamePixelAndChannelCount(roiImg) ) {
359  LabelRelease_();
360  LabelInit_(roiImg);
361  }
362  ImageConvert::ConvertST( roiImg, LabelSumImage_ ,LABEL_STORAGE_TYPE);
363  // ImageIO::Save("lsi-"+os.str()+".mip", LabelSumImage_);
364 
365  int width, height;
366  width=LabelResultImage_.GetWidth();
367  height=LabelResultImage_.GetHeight();
368  BIASCDOUT(D_LABEL, "image size: "<<width<<"x"<<height<<endl);
369  //LabelResultImage_.FillImageWithConstValue(0);
370  //coun++;
371  int count = Label4Neighbour_();
372  //ImageIO::Save("lri-"+os.str()+".mip", LabelResultImage_);
373 
374  BIASCDOUT(D_LABEL, "found "<<count<<" blobs\n");
375  BlobCount_.clear();
376  BlobMap_.clear();
377  TopLefts_.clear();
378  BotRights_.clear();
379  Centers_.clear();
380  MedianCenters_.clear();
381 
382  if (count<=0) {
383  BlobCount_.push_back(0);
384  } else {
385  //ImageIO::Save("sim.mip", LabelResultImage_);
386  // initialize data structs
387  BlobCount_.resize(count-1);
388  TopLefts_.resize(count-1);
389  BotRights_.resize(count-1);
390  Centers_.resize(count-1);
391  MedianCenters_.resize(count-1);
392  SortVec_.resize(count);
393  Num_.clear();
394  for (int n=0; n<count; n++){
395  SortVec_[n].bc=0;
396  SortVec_[n].tl.Set(width, height);
397  SortVec_[n].br.Set(0, 0);
398  SortVec_[n].center.Set(0.0, 0.0);
399  SortVec_[n].x.clear();
400  SortVec_[n].y.clear();
401  }
402  // now get values
403  LABEL_CALC_TYPE **ida=LabelResultImage_.GetImageDataArray();
404  LABEL_CALC_TYPE c;
405  unsigned int i;
406  for (int y=0; y<height; y++){
407  for (int x=0; x<width; x++){
408  c=ida[y][x];
409  // find the correct SortVec index
410  i=0;
411  while (i<Num_.size() && Num_[i]!=c) i++;
412  // create SortVec it if not found
413  if (i==Num_.size()) Num_.push_back(c);
414  // fill SortVec_[i]
415  /*if (SortVec_[i].bc>10000){
416  cout << SortVec_[i].bc<<" : c: "<<c<<"\ti="<<i<<" "<<Num_.size()
417  <<" "<<SortVec_.size()<<endl;
418  }*/
419  SortVec_[i].bc++; // BlobCount_[i]++;
420  SortVec_[i].center += Vector2<double>((double)x, (double)y);
421  SortVec_[i].x.push_back(x);
422  SortVec_[i].y.push_back(y);
423  if (SortVec_[i].tl[0]>x) SortVec_[i].tl[0]=x;
424  if (SortVec_[i].tl[1]>y) SortVec_[i].tl[1]=y;
425  if (SortVec_[i].br[0]<x) SortVec_[i].br[0]=x;
426  if (SortVec_[i].br[1]<y) SortVec_[i].br[1]=y;
427  }
428  }
429 
430  sort(SortVec_.begin(), SortVec_.end());
431  const Vector2<double> offset((double)minx, (double)miny);
432  BIASCDOUT(D_LABEL, "neglecting bg label: "<<SortVec_[0].center <<"\t"
433  << (double)SortVec_[0].bc << "\t"<<SortVec_[0].tl<<"\t"
434  << SortVec_[0].br
435  << (SortVec_[0].center / (double)SortVec_[0].bc) <<"\t"
436  <<endl);
437  static Median1D<int> med;
438  double mx, my;
439  for (int i=1, j=0; i<count; i++, j++){
440  BlobCount_[j]=SortVec_[i].bc;
441  BlobMap_[i]=SortVec_[i].bc;
442  TopLefts_[j]=SortVec_[i].tl;
443  BotRights_[j]=SortVec_[i].br;
444  Centers_[j] = (SortVec_[i].center / (double)SortVec_[i].bc) + offset;
445  med.Compute(SortVec_[i].x);
446  mx = (double)med.GetMedian() + offset[0];
447  med.Compute(SortVec_[i].y);
448  my = (double)med.GetMedian() + offset[1];
449  MedianCenters_[j] = Vector2<double>(mx, my);
450  //cout << "c: "<<Centers_[j]<<"\tmc: "<<MedianCenters_[j]<<endl;
451  BIASCDOUT(D_LABEL, SortVec_[i].center <<"\t"
452  << (double)SortVec_[i].bc << "\t"<<Centers_[j] <<"\t"
453  << SortVec_[i].tl <<"\t"<< SortVec_[i].br<< "\t"
454  << (SortVec_[i].center / (double)SortVec_[i].bc) <<"\n");
455  }
456  }
457  return 0;
458 }
459 
461 {
462  BIASCDOUT(D_FILTERBASE_CALLSTACK, "Label::Filter\n");
463 
464  Process(src);
465  if (BlobCount_.size()>255) {
466  BIASERR("Label.Filter(): resulting image invalid, cause more than 255 "
467  "regions");
468  }
469  bool UseLargeImage = false;
470  Image<LABEL_CALC_TYPE> LargeImage;
471  if (!LabelResultImage_.SamePixelAndChannelCount(src)) {
472  LargeImage.Init(src.GetWidth(), src.GetHeight(), 1);
473  unsigned int UpperLeftX, UpperLeftY, LowerRightX, LowerRightY;
474  src.GetROI()->GetCorners(UpperLeftX, UpperLeftY, LowerRightX, LowerRightY);
475  LargeImage.GetROI()->SetCorners(UpperLeftX, UpperLeftY, LowerRightX, LowerRightY);
476  LargeImage.Paste2ROI(LabelResultImage_);
477  UseLargeImage = true;
478  }
479 
480  if (!dst.SamePixelAndChannelCount(src)) {
481  if (!dst.IsEmpty()) dst.Release();
482  dst.Init(src.GetWidth(), src.GetHeight(), 1);
483  }
484 
485  if (UseLargeImage) ImageConvert::ConvertST(LargeImage, dst,
487  else ImageConvert::ConvertST(LabelResultImage_, dst,
489  return 0;
490 }
491 
492 void Label::
493 GetBordersValid_(int& border_x, int& border_y) const
494 {
495  border_x = border_y = 0;
496 }
497 
498 
int GetCopyOfROI(ImageBase &copy) const
returns a copy of ROI (a new image) lower right point excluded, only interleaved images ! ...
Definition: ImageBase.cpp:568
void Release()
reimplemented from ImageBase
Definition: Image.cpp:1579
void LabelInit_(const ImageBase &Image)
Definition: Label.cpp:66
DataType GetMedian() const
Return computed median.
Definition: Median1D.hh:56
int SetCorners(unsigned UpperLeftX, unsigned UpperLeftY, unsigned LowerRightX, unsigned LowerRightY)
Sets a rectangular region of interest.
Definition: ROI.cpp:287
void GetCorners(unsigned &UpperLeftX, unsigned &UpperLeftY, unsigned &LowerRightX, unsigned &LowerRightY) const
Return the region of interest, by saving the coordinates within the variables defined by the paramete...
Definition: ROI.hh:443
bool IsEmpty() const
check if ImageData_ points to allocated image buffer or not
Definition: ImageBase.hh:245
Computes the median and p-quantile of a vector.
Definition: Median1D.hh:41
int Label4Neighbour(const BIAS::Image< unsigned char > &Image, BIAS::Image< unsigned char > &DestinationImage)
labels an unsigned short int using an 4er neighbourhood and returns it in DestinationImage if Destina...
Definition: Label.cpp:308
int Process(const Image< unsigned char > &im)
call this if you don&#39;t need the output image, is faster than Filter
Definition: Label.cpp:344
int Label4Neighbour_()
Definition: Label.cpp:110
unsigned int GetWidth() const
Definition: ImageBase.hh:312
virtual int Filter(const Image< unsigned char > &src, Image< unsigned char > &dst)
prototyp for filter computation function
Definition: Label.cpp:460
ROI * GetROI()
Returns a pointer to the roi object.
Definition: ImageBase.hh:615
void LabelRelease_()
Definition: Label.cpp:100
static int ConvertST(const BIAS::ImageBase &source, BIAS::ImageBase &dest, ImageBase::EStorageType targetST)
Function to convert the storage type of images e.g.
void Compute(const std::vector< DataType > &vec)
Compute median and store sorted vector internally.
Definition: Median1D.cpp:32
unsigned int GetHeight() const
Definition: ImageBase.hh:319
The image template class for specific storage types.
Definition: Image.hh:78
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
(8bit) unsigned char image storage type
Definition: ImageBase.hh:112
int Paste2ROI(const ImageBase &Image)
paste Image to current ROI
Definition: ImageBase.cpp:603
This is the base class for images in BIAS.
Definition: ImageBase.hh:102
virtual void GetBordersValid_(int &border_x, int &border_y) const
Definition: Label.cpp:493