Basic Image AlgorithmS Library  2.8.0
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
BlobDetectorCCA.cpp
1 #include <algorithm>
2 #include "BlobDetectorCCA.hh"
3 #include "Base/Image/ImageConvert.hh"
4 
5 
6 /**
7  CCA : Connected Component Analysis
8  @author Daniel grest, Sept. 2002
9  */
10 #define D_EACHP 1<<0
11 #define D_REGION 1<<1
12 
13 
14 using namespace BIAS;
15 using namespace std;
16 
17 namespace BIAS{
18 /**
19  * \class Compare
20  * \brief simple class so compare vector sizes
21  * \internal
22  */
23 class Compare {
24 public:
25  bool operator()(const std::vector<Vector2<int> > &left,
26  const std::vector<Vector2<int> > &right) const {
27  if (left.size()>right.size()) return true;
28  else return false;
29  }
30  bool operator()(const std::vector<unsigned int> &left,
31  const std::vector<unsigned int> &right) const {
32  if (left.size()>right.size()) return true;
33  else return false;
34  }
35 }; // endof class Compare
36 }//end namespace BIAS
37 
38 ///////////////////////////////////////////////////////////////////
39 
40 
41 template <class StorageType>
44  bIsInited_=false;
45  fPercent_=50;
46  bNeighborHood4_=true;
47 }
48 
49 template <class StorageType>
52 }
53 
54 
55 template <class StorageType> int
58  std::vector<BIAS::BIASBlob>& blobs){
59  int ret =0;
60  Init_(image);
61  ret = Process_(image,fPercent_, bNeighborHood4_);
62  std::vector<BIAS::Vector2<double> > centroids;
63  GetCentroids(centroids);
64  BIASBlob blob;
65  blobs.clear();
66  for(unsigned int i=0;i<centroids.size();i++){
67  blob.UL[0] = (double)TopLefts_[i][0];
68  blob.UL[1] = (double)TopLefts_[i][1];
69  blob.LR[0] = (double)BotRights_[i][0];
70  blob.LR[1] = (double)BotRights_[i][1];
71  blob.weight = 0;
72  blob.centerofmass = centroids[i];
73  blobs.push_back(blob);
74  }
75  return ret;
76 }
77 
78 
79 template <class StorageType> void
82  Label::LabelInit_(img);
83  bIsInited_=true;
84 }
85 
86 
87 template <class StorageType> int
89 Process_(Image<StorageType> &img, float percent,
90  bool neighborHood4)
91 {
92 
93  unsigned int pixelAllowed= (unsigned int)((float)img.GetPixelCount()
94  * (percent / 100.0) + 0.5);
95 #ifdef BIAS_DEBUG
96  if (img.GetChannelCount() !=1) {
97  BIASERR("Filter::CCA() only implemented for grey images");
98  return -1;
99  }
100 #endif
101  ImageConvert::ConvertST(img, LabelSumImage_ , LABEL_STORAGE_TYPE);
102 
103  int count=Label4Neighbour_();
104 #ifdef BIAS_DEBUG
105  if (count>=255)
106  BIASERR("WARNING: CCA: 255 blobs found, there are probably more."<<
107  "If so, CCA did not work correctly, "<<
108  "make sure there are less regions!");
109 #endif
110  BIASCDOUT(D_LABEL, "found "<<count<<" blobs");
111  BlobCount_.clear();
112  TopLefts_.clear();
113  BotRights_.clear();
114 
115  LABEL_CALC_TYPE **ida=LabelResultImage_.GetImageDataArray();
116  int width, height;
117  width=LabelResultImage_.GetWidth();
118  height=LabelResultImage_.GetHeight();
119  if (count==0) {
120  BlobCount_.push_back(0);
121  } else {
122  //ImageIO::Save("sim.mip", LabelResultImage_);
123  // initialize data structs
124  BlobCount_.resize(count);
125  TopLefts_.resize(count);
126  BotRights_.resize(count);
127  SortVec_.resize(count);
128  allBlobs_.resize(count);
129  Num_.clear();
130 
131  for (int ii=0; ii<count; ii++){
132  SortVec_[ii].bc=0;
133  SortVec_[ii].tl.Set(width, height);
134  SortVec_[ii].br.Set(0, 0);
135  }
136  // now get values
137 
138 
139  LABEL_CALC_TYPE c=0, i=0;
140 
141  for (int y=0; y<height; y++) {
142  for (int x=0; x<width; x++) {
143  c=ida[y][x];
144  i=0;
145  while ((unsigned int)i<Num_.size() && Num_[i]!=c) i++;
146  if ((unsigned int)i==Num_.size()) Num_.push_back(c);
147  SortVec_[i].bc++; // BlobCount_[i]++;
148  if (SortVec_[i].tl[0]>x) SortVec_[i].tl[0]=x;
149  if (SortVec_[i].tl[1]>y) SortVec_[i].tl[1]=y;
150  if (SortVec_[i].br[0]<x) SortVec_[i].br[0]=x;
151  if (SortVec_[i].br[1]<y) SortVec_[i].br[1]=y;
152  allBlobs_[i].push_back(BIAS::Vector2<int>(x,y));
153  }
154  }
155  sort(SortVec_.begin(), SortVec_.end());
156  for (int ii=0; ii<count; ii++) {
157  BlobCount_[ii]=SortVec_[ii].bc;
158  TopLefts_[ii]=SortVec_[ii].tl;
159  BotRights_[ii]=SortVec_[ii].br;
160  }
161  }
162 
163  //// now delete small regions
164  sort(allBlobs_.begin(), allBlobs_.end(), Compare());
165  StorageType **data=img.GetImageDataArray();
166  if (percent<0) { // delete all except first region
167  for (unsigned int r=2;r<allBlobs_.size();r++)
168  for (unsigned int p=0;p<allBlobs_[r].size();p++)
169  data[allBlobs_[r][p][1]][allBlobs_[r][p][0]]=0;
170  } else { // delete too small regions
171  for (unsigned int r=0;r<allBlobs_.size();r++)
172  if ((unsigned int)(BlobCount_[r])<pixelAllowed)
173  for (unsigned int p=0;p<allBlobs_[r].size();p++)
174  data[allBlobs_[r][p][1]][allBlobs_[r][p][0]]=0;
175  }
176 
177  return 0;
178 }
179 
180 template <class StorageType> int
182 Process8_(Image<StorageType> &/*img*/, float /*percent*/)
183 {
184 #ifdef BIAS_DEBUG
185  BIASERR("8 neighborhood not yet implemented");
186 #endif
187 
188  return -1;
189 }
190 
191 template <class StorageType> int
193 GetCentroids(std::vector<BIAS::Vector2<double> > &centroids) {
194  centroids.clear();
195  if (allBlobs_.size()<1) {
196  return 0;
197  }
198  BIAS::Vector2<double> center;
199  for (unsigned int r=0;r<allBlobs_.size();r++) {
200  center[0]=0; center[1]=0;
201  for (unsigned int i=0;i<allBlobs_[r].size();i++) {
202  center[0]+= allBlobs_[r][i][0];
203  center[1]+= allBlobs_[r][i][1];
204  }
205  center[0]/=(double)(allBlobs_[r].size());
206  center[1]/=(double)(allBlobs_[r].size());
207  centroids.push_back(center);
208  }
209  return 0;
210 }
211 
212 template <class StorageType> int
215 {
216  medians.clear();
217  if (allBlobs_.size()<1) {
218  return 0;
219  }
220  std::vector<unsigned int> xValues, yValues;
221  xValues.reserve(allBlobs_[0].size());
222  yValues.reserve(allBlobs_[0].size());
223 
225  for (unsigned int r=0;r<allBlobs_.size();r++) {
226  xValues.clear(); yValues.clear();
227  for (unsigned int i=0;i<allBlobs_[r].size();i++) {
228  xValues.push_back( allBlobs_[r][i][0]);
229  yValues.push_back( allBlobs_[r][i][1]);
230  }
231  sort(xValues.begin(), xValues.end());
232  center[0]=xValues[xValues.size() / 2];
233  center[1]=yValues[yValues.size() / 2];
234  medians.push_back(center);
235  }
236  return 0;
237 }
238 
239 
240 //////////////////////////////////////////////////////////////////////////
241 // instantiation
242 //////////////////////////////////////////////////////////////////////////
243 namespace BIAS{
244 template class BlobDetectorCCA<unsigned char>;
245 template class BlobDetectorCCA<float>;
246 
247 // fill in instances as required
248 #ifdef BUILD_IMAGE_INT
249 template class BlobDetectorCCA<int>;
250 #endif
251 #ifdef BUILD_IMAGE_CHAR
252 //template class BlobDetectorCCA<char>;
253 #endif
254 #ifdef BUILD_IMAGE_SHORT
255 #endif
256 #ifdef BUILD_IMAGE_USHORT
257 //template class BlobDetectorCCA<unsigned short>;
258 #endif
259 #ifdef BUILD_IMAGE_UINT
260 #endif
261 #ifdef BUILD_IMAGE_DOUBLE
262 #endif
263 }
unsigned int weight
void LabelInit_(const ImageBase &Image)
Definition: Label.cpp:66
int GetCentroids(std::vector< BIAS::Vector2< double > > &centroids)
call this afer Process() to get the centroids of all regions.
int Detect(Image< StorageType > &image, std::vector< BIAS::BIASBlob > &blobs)
Does a Connected Component Analyis (4-neighborhood) and deletes all regions, whose sizes are smaller ...
BIAS::Vector2< double > LR
int GetMedians(std::vector< BIAS::Vector2< unsigned int > > &medians)
call this afer Process() to get the medians of all regions.
Helper class to store blob corners.
int Process_(BIAS::Image< StorageType > &img, float percent, bool neighborHood4=true)
void Init_(const BIAS::Image< StorageType > &img)
init is called before processing the first image
static int ConvertST(const BIAS::ImageBase &source, BIAS::ImageBase &dest, ImageBase::EStorageType targetST)
Function to convert the storage type of images e.g.
BIAS::Vector2< double > centerofmass
unsigned int GetChannelCount() const
returns the number of Color channels, e.g.
Definition: ImageBase.hh:382
The image template class for specific storage types.
Definition: Image.hh:78
BIAS::Vector2< double > UL
unsigned long int GetPixelCount() const
returns number of pixels in image
Definition: ImageBase.hh:422
int Process8_(BIAS::Image< StorageType > &img, float percent)
Does a Connected Component Analyis and gives information about regions in an image, like centroid and bounding boxes.
const StorageType ** GetImageDataArray() const
overloaded GetImageDataArray() from ImageBase
Definition: Image.hh:153