DGtalTools  0.9.4
img2freeman.cpp
1 #include "DGtal/io/colormaps/GrayscaleColorMap.h"
2 #include "DGtal/io/readers/GenericReader.h"
3 
4 
5 #include "DGtal/images/ImageContainerBySTLVector.h"
6 
7 #include "DGtal/images/ImageSelector.h"
8 
9 #include "DGtal/geometry/curves/FreemanChain.h"
10 #include "DGtal/geometry/helpers/ContourHelper.h"
11 
12 #include "DGtal/topology/helpers/Surfaces.h"
13 
14 #include <boost/program_options/options_description.hpp>
15 #include <boost/program_options/parsers.hpp>
16 #include <boost/program_options/variables_map.hpp>
17 
18 #include <vector>
19 #include <string>
20 #include <climits>
21 
22 
23 using namespace DGtal;
95 namespace po = boost::program_options;
97 
98 
100 
101 
102 
103 std::vector<unsigned int> getHistoFromImage(const Image &image){
104  const Image::Domain &imgDom = image.domain();
105  std::vector<unsigned int> vectHisto(UCHAR_MAX);
106  for(Image::Domain::ConstIterator it=imgDom.begin(); it!= imgDom.end(); ++it){
107  vectHisto[image(*it)]++;
108  }
109  return vectHisto;
110 }
111 
112 
113 
114 unsigned int
115 getOtsuThreshold(const Image &image){
116  std::vector<unsigned int> histo = getHistoFromImage(image);
117  unsigned int imageSize = image.domain().size();
118  unsigned int sumA = 0;
119  unsigned int sumB = imageSize;
120  unsigned int muA=0;
121  unsigned int muB=0;
122  unsigned int sumMuAll= 0;
123  for( unsigned int t=0; t< histo.size();t++){
124  sumMuAll+=histo[t]*t;
125  }
126 
127  unsigned int thresholdRes=0;
128  double valMax=0.0;
129  for( unsigned int t=0; t< histo.size(); t++){
130  sumA+=histo[t];
131  if(sumA==0)
132  continue;
133  sumB=imageSize-sumA;
134  if(sumB==0){
135  break;
136  }
137 
138  muA+=histo[t]*t;
139  muB=sumMuAll-muA;
140  double muAr=muA/(double)sumA;
141  double muBr=muB/(double)sumB;
142  double sigma= (double)sumA*(double)sumB*(muAr-muBr)*(muAr-muBr);
143  if(valMax<=sigma){
144  valMax=sigma;
145  thresholdRes=t;
146  }
147  }
148  return thresholdRes;
149 }
150 
151 struct CompContours{
152  bool operator()(std::vector<Z2i::Point> a, std::vector<Z2i::Point> b ){
153  return a.size() > b.size();
154  }
155 };
156 
157 
158 void saveAllContoursAsFc( std::vector< std::vector< Z2i::Point > > vectContoursBdryPointels,
159  unsigned int minSize, bool sort=false){
160  CompContours comp;
161  if(sort){
162  std::sort(vectContoursBdryPointels.begin(), vectContoursBdryPointels.end(), comp);
163  }
164  for(unsigned int k=0; k<vectContoursBdryPointels.size(); k++){
165  if(vectContoursBdryPointels.at(k).size()>minSize){
166  FreemanChain<Z2i::Integer> fc (vectContoursBdryPointels.at(k));
167  std::cout << fc.x0 << " " << fc.y0 << " " << fc.chain << std::endl;
168 
169  }
170  }
171 }
172 
173 
174 void saveSelContoursAsFC(std::vector< std::vector< Z2i::Point > > vectContoursBdryPointels,
175  unsigned int minSize, Z2i::Point refPoint, double selectDistanceMax,
176  bool sort=false){
177  CompContours comp;
178  if(sort){
179  std::sort(vectContoursBdryPointels.begin(), vectContoursBdryPointels.end(), comp);
180  }
181 
182  for(unsigned int k=0; k<vectContoursBdryPointels.size(); k++){
183  if(vectContoursBdryPointels.at(k).size()>minSize){
184  Z2i::Point ptMean = ContourHelper::getBarycenter(vectContoursBdryPointels.at(k));
185  unsigned int distance = (unsigned int)ceil(sqrt((double)(ptMean[0]-refPoint[0])*(ptMean[0]-refPoint[0])+
186  (ptMean[1]-refPoint[1])*(ptMean[1]-refPoint[1])));
187  if(distance<=selectDistanceMax){
188  FreemanChain<Z2i::Integer> fc (vectContoursBdryPointels.at(k));
189  std::cout << fc.x0 << " " << fc.y0 << " " << fc.chain << std::endl;
190  }
191  }
192  }
193 }
194 
195 
196 
197 
198 int main( int argc, char** argv )
199 {
200  // parse command line ----------------------------------------------
201  po::options_description general_opt("Allowed options are ");
202  general_opt.add_options()
203  ("help,h", "display this message")
204  ("input,i", po::value<std::string>(), "image file name")
205  ("min,m", po::value<int>(), "min image threshold value (default 128)")
206  ("max,M", po::value<int>(), "max image threshold value (default 255)")
207  ("sort", "to sort the resulting freemanchain by decreasing size.")
208  ("minSize,s", po::value<int>(), "minSize of the extracted freeman chain (default 0)")
209  ("contourSelect,c", po::value<std::vector <int> >()->multitoken(),
210  "Select contour according reference point and maximal distance: ex. --contourSelect X Y distanceMax")
211  ("thresholdRangeMin,r", po::value<std::vector <int> >()->multitoken(),
212  "use a range interval as threshold (from min) : --thresholdRangeMin min increment max : for each possible i, it define a digital sets [min, min+((i+1)*increment)] such that min+((i+1)*increment)< max and extract their boundary. ")
213  ("thresholdRangeMax,R", po::value<std::vector <int> >()->multitoken(),
214  "use a range interval as threshold (from max) : --thresholdRangeMax min increment max : for each possible i, it define a digital sets [ max-((i)*increment), max] such that max-((i)*increment)>min and extract their boundary. ");
215 
216  bool parseOK=true;
217  po::variables_map vm;
218  try{
219  po::store(po::parse_command_line(argc, argv, general_opt), vm);
220  }catch(const std::exception& ex){
221  trace.info()<< "Error checking program options: "<< ex.what()<< std::endl;
222  parseOK=false;
223  }
224  po::notify(vm);
225  if(vm.count("help")||argc<=1|| !parseOK)
226  {
227  trace.info()<< "Extract FreemanChains from thresholded image" <<std::endl << "Basic usage: "<<std::endl
228  << "\t img2freeman [options] --input <imageName> -min 128 -max 255 > contours.fc"<<std::endl
229  << "Note that if you don't specify any threshold a threshold threshold max is automatically defined from the Otsu algorithm with min=0. "<<std::endl
230  << general_opt << "\n";
231  return 0;
232  }
233 
234  double minThreshold = 128;
235  double maxThreshold = 255;
236  unsigned int minSize =0;
237  bool select=false;
238  bool sortCnt = vm.count("sort");
239  bool thresholdRange=vm.count("thresholdRangeMin")||vm.count("thresholdRangeMax");
240  Z2i::Point selectCenter;
241  unsigned int selectDistanceMax = 0;
242 
244  std::string imageFileName = vm["input"].as<std::string>();
245 
246  Image image = GenericReader<Image>::import( imageFileName );
247 
248 
249  //Parse options
250  if (!(vm.count("input"))){
251  trace.info() << "Image file name needed"<< std::endl;
252  return 0;
253  }
254  if(vm.count("min")){
255  minThreshold= vm["min"].as<int>();
256  }
257  if(vm.count("max")){
258  maxThreshold= vm["max"].as<int>();
259  }
260  if(vm.count("minSize")){
261  minSize = vm["minSize"].as<int>();
262  }
263  if(vm.count("contourSelect")){
264  select=true;
265  std::vector<int> cntConstraints= vm["contourSelect"].as<std::vector <int> >();
266  if(cntConstraints.size()!=3){
267  trace.info() << "Incomplete option \"--contourSelect\""<< std::endl;
268  return 0;
269  }
270  selectCenter[0]= cntConstraints.at(0);
271  selectCenter[1]= cntConstraints.at(1);
272  selectDistanceMax= (unsigned int) cntConstraints.at(2);
273  }
274 
275  int min, max, increment;
276  if(! thresholdRange){
277  min=(int)minThreshold;
278  max= (int)maxThreshold;
279  increment = (int)(maxThreshold - minThreshold);
280  if(!vm.count("min")&&!vm.count("max")) {
281  min=0;
282  trace.info() << "Min/Max threshold values not specified, set min to 0 and computing max with the otsu algorithm...";
283  max = getOtsuThreshold(image);
284  trace.info() << "[done] (max= " << max << ") "<< std::endl;
285  }
286 
287  }else{
288  std::vector<int> vectRange;
289  if ( vm.count("thresholdRangeMax")){
290  vectRange= vm["thresholdRangeMax"].as<std::vector <int> >();
291  }else{
292  vectRange= vm["thresholdRangeMin"].as<std::vector <int> >();
293  }
294  if(vectRange.size()!=3){
295  trace.info() << "Incomplete option \"--thresholdRange\""<< std::endl;
296  return 0;
297  }
298  min=vectRange.at(0);
299  increment=vectRange.at(1);
300  max = vectRange.at(2);
301  minThreshold=min;
302  maxThreshold=max;
303  }
304 
305 
306 
307 
308  Z2i::KSpace ks;
309  if(! ks.init( image.domain().lowerBound(),
310  image.domain().upperBound(), true )){
311  trace.error() << "Problem in KSpace initialisation"<< std::endl;
312  }
313 
314 
315  if (!thresholdRange){
316  Binarizer b(min, max);
318  trace.info() << "DGtal contour extraction from thresholds ["<< min << "," << max << "]" ;
319  SurfelAdjacency<2> sAdj( true );
320  std::vector< std::vector< Z2i::Point > > vectContoursBdryPointels;
321  Surfaces<Z2i::KSpace>::extractAllPointContours4C( vectContoursBdryPointels,
322  ks, predicate, sAdj );
323  if(select){
324  saveSelContoursAsFC(vectContoursBdryPointels, minSize, selectCenter, selectDistanceMax, sortCnt);
325  }else{
326  saveAllContoursAsFc(vectContoursBdryPointels, minSize, sortCnt);
327  }
328  }else{
329  for(int i=0; minThreshold+i*increment< maxThreshold; i++){
330  if(vm.count("thresholdRangeMin")){
331  min = (int)(minThreshold+(i)*increment);
332  }
333  if(vm.count("thresholdRangeMax")){
334  max = (int)(maxThreshold-(i)*increment);
335  }
336  Binarizer b(min, max);
338 
339  trace.info() << "DGtal contour extraction from thresholds ["<< min << "," << max << "]" ;
340  SurfelAdjacency<2> sAdj( true );
341  std::vector< std::vector< Z2i::Point > > vectContoursBdryPointels;
342  Surfaces<Z2i::KSpace>::extractAllPointContours4C( vectContoursBdryPointels,
343  ks, predicate, sAdj );
344  if(select){
345  saveSelContoursAsFC(vectContoursBdryPointels, minSize, selectCenter, selectDistanceMax, sortCnt);
346  }else{
347  saveAllContoursAsFc(vectContoursBdryPointels, minSize, sortCnt);
348  }
349  trace.info() << " [done]" << std::endl;
350  }
351  }
352 
353 
354 
355 }
356 
static void extractAllPointContours4C(std::vector< std::vector< Point > > &aVectPointContour2D, const KSpace &aKSpace, const PointPredicate &pp, const SurfelAdjacency< 2 > &aSAdj)
static TContainer import(const std::string &filename, std::vector< unsigned int > dimSpace=std::vector< unsigned int >())
bool init(const Point &lower, const Point &upper, bool isClosed)
Trace trace(traceWriterTerm)
std::ostream & info()
std::vector< Value >::const_iterator ConstIterator
const Domain & domain() const
std::ostream & error()