1 #include "DGtal/io/colormaps/GrayscaleColorMap.h"
2 #include "DGtal/io/readers/GenericReader.h"
5 #include "DGtal/images/ImageContainerBySTLVector.h"
7 #include "DGtal/images/ImageSelector.h"
9 #include "DGtal/geometry/curves/FreemanChain.h"
10 #include "DGtal/geometry/helpers/ContourHelper.h"
12 #include "DGtal/topology/helpers/Surfaces.h"
14 #include <boost/program_options/options_description.hpp>
15 #include <boost/program_options/parsers.hpp>
16 #include <boost/program_options/variables_map.hpp>
23 using namespace DGtal;
95 namespace po = boost::program_options;
103 std::vector<unsigned int> getHistoFromImage(
const Image &image){
105 std::vector<unsigned int> vectHisto(UCHAR_MAX);
107 vectHisto[image(*it)]++;
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;
122 unsigned int sumMuAll= 0;
123 for(
unsigned int t=0; t< histo.size();t++){
124 sumMuAll+=histo[t]*t;
127 unsigned int thresholdRes=0;
129 for(
unsigned int t=0; t< histo.size(); t++){
140 double muAr=muA/(double)sumA;
141 double muBr=muB/(double)sumB;
142 double sigma= (double)sumA*(
double)sumB*(muAr-muBr)*(muAr-muBr);
152 bool operator()(std::vector<Z2i::Point> a, std::vector<Z2i::Point> b ){
153 return a.size() > b.size();
158 void saveAllContoursAsFc( std::vector< std::vector< Z2i::Point > > vectContoursBdryPointels,
159 unsigned int minSize,
bool sort=
false){
162 std::sort(vectContoursBdryPointels.begin(), vectContoursBdryPointels.end(), comp);
164 for(
unsigned int k=0; k<vectContoursBdryPointels.size(); k++){
165 if(vectContoursBdryPointels.at(k).size()>minSize){
167 std::cout << fc.
x0 <<
" " << fc.y0 <<
" " << fc.chain << std::endl;
174 void saveSelContoursAsFC(std::vector< std::vector< Z2i::Point > > vectContoursBdryPointels,
175 unsigned int minSize,
Z2i::Point refPoint,
double selectDistanceMax,
179 std::sort(vectContoursBdryPointels.begin(), vectContoursBdryPointels.end(), comp);
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){
189 std::cout << fc.
x0 <<
" " << fc.y0 <<
" " << fc.chain << std::endl;
198 int main(
int argc,
char** argv )
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. ");
217 po::variables_map vm;
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;
225 if(vm.count(
"help")||argc<=1|| !parseOK)
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";
234 double minThreshold = 128;
235 double maxThreshold = 255;
236 unsigned int minSize =0;
238 bool sortCnt = vm.count(
"sort");
239 bool thresholdRange=vm.count(
"thresholdRangeMin")||vm.count(
"thresholdRangeMax");
241 unsigned int selectDistanceMax = 0;
244 std::string imageFileName = vm[
"input"].as<std::string>();
250 if (!(vm.count(
"input"))){
251 trace.
info() <<
"Image file name needed"<< std::endl;
255 minThreshold= vm[
"min"].as<
int>();
258 maxThreshold= vm[
"max"].as<
int>();
260 if(vm.count(
"minSize")){
261 minSize = vm[
"minSize"].as<
int>();
263 if(vm.count(
"contourSelect")){
265 std::vector<int> cntConstraints= vm[
"contourSelect"].as<std::vector <int> >();
266 if(cntConstraints.size()!=3){
267 trace.
info() <<
"Incomplete option \"--contourSelect\""<< std::endl;
270 selectCenter[0]= cntConstraints.at(0);
271 selectCenter[1]= cntConstraints.at(1);
272 selectDistanceMax= (
unsigned int) cntConstraints.at(2);
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")) {
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;
288 std::vector<int> vectRange;
289 if ( vm.count(
"thresholdRangeMax")){
290 vectRange= vm[
"thresholdRangeMax"].as<std::vector <int> >();
292 vectRange= vm[
"thresholdRangeMin"].as<std::vector <int> >();
294 if(vectRange.size()!=3){
295 trace.
info() <<
"Incomplete option \"--thresholdRange\""<< std::endl;
299 increment=vectRange.at(1);
300 max = vectRange.at(2);
309 if(! ks.
init( image.domain().lowerBound(),
310 image.domain().upperBound(), true )){
311 trace.
error() <<
"Problem in KSpace initialisation"<< std::endl;
315 if (!thresholdRange){
316 Binarizer b(min, max);
318 trace.
info() <<
"DGtal contour extraction from thresholds ["<< min <<
"," << max <<
"]" ;
320 std::vector< std::vector< Z2i::Point > > vectContoursBdryPointels;
322 ks, predicate, sAdj );
324 saveSelContoursAsFC(vectContoursBdryPointels, minSize, selectCenter, selectDistanceMax, sortCnt);
326 saveAllContoursAsFc(vectContoursBdryPointels, minSize, sortCnt);
329 for(
int i=0; minThreshold+i*increment< maxThreshold; i++){
330 if(vm.count(
"thresholdRangeMin")){
331 min = (int)(minThreshold+(i)*increment);
333 if(vm.count(
"thresholdRangeMax")){
334 max = (int)(maxThreshold-(i)*increment);
336 Binarizer b(min, max);
339 trace.
info() <<
"DGtal contour extraction from thresholds ["<< min <<
"," << max <<
"]" ;
341 std::vector< std::vector< Z2i::Point > > vectContoursBdryPointels;
343 ks, predicate, sAdj );
345 saveSelContoursAsFC(vectContoursBdryPointels, minSize, selectCenter, selectDistanceMax, sortCnt);
347 saveAllContoursAsFc(vectContoursBdryPointels, minSize, sortCnt);
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::vector< Value >::const_iterator ConstIterator
const Domain & domain() const