1 #include "DGtal/io/colormaps/GrayscaleColorMap.h"
2 #include "DGtal/io/readers/GenericReader.h"
3 #include "DGtal/images/ImageContainerBySTLVector.h"
4 #include "DGtal/images/ImageSelector.h"
5 #include "DGtal/geometry/curves/FreemanChain.h"
6 #include "DGtal/geometry/helpers/ContourHelper.h"
7 #include "DGtal/topology/helpers/Surfaces.h"
16 using namespace DGtal;
77 typedef ImageSelector < Z2i::Domain, unsigned char>::Type Image;
80 std::vector<unsigned int> getHistoFromImage(
const Image &image){
81 const Image::Domain &imgDom = image.domain();
82 std::vector<unsigned int> vectHisto(UCHAR_MAX);
83 for(Image::Domain::ConstIterator it=imgDom.begin(); it!= imgDom.end(); ++it){
84 vectHisto[image(*it)]++;
90 getOtsuThreshold(
const Image &image){
91 std::vector<unsigned int> histo = getHistoFromImage(image);
92 unsigned int imageSize = image.domain().size();
93 unsigned int sumA = 0;
94 unsigned int sumB = imageSize;
97 unsigned int sumMuAll= 0;
98 for(
unsigned int t=0; t< histo.size();t++){
102 unsigned int thresholdRes=0;
104 for(
unsigned int t=0; t< histo.size(); t++){
115 double muAr=muA/(double)sumA;
116 double muBr=muB/(double)sumB;
117 double sigma= (double)sumA*(
double)sumB*(muAr-muBr)*(muAr-muBr);
127 bool operator()(std::vector<Z2i::Point> a, std::vector<Z2i::Point> b ){
128 return a.size() > b.size();
133 void saveAllContoursAsFc( std::vector< std::vector< Z2i::Point > > vectContoursBdryPointels,
134 unsigned int minSize,
bool sort=
false){
137 std::sort(vectContoursBdryPointels.begin(), vectContoursBdryPointels.end(), comp);
139 for(
unsigned int k=0; k<vectContoursBdryPointels.size(); k++){
140 if(vectContoursBdryPointels.at(k).size()>minSize){
141 FreemanChain<Z2i::Integer> fc (vectContoursBdryPointels.at(k));
142 std::cout << fc.x0 <<
" " << fc.y0 <<
" " << fc.chain << std::endl;
149 void saveSelContoursAsFC(std::vector< std::vector< Z2i::Point > > vectContoursBdryPointels,
150 unsigned int minSize, Z2i::Point refPoint,
double selectDistanceMax,
154 std::sort(vectContoursBdryPointels.begin(), vectContoursBdryPointels.end(), comp);
157 for(
unsigned int k=0; k<vectContoursBdryPointels.size(); k++){
158 if(vectContoursBdryPointels.at(k).size()>minSize){
159 Z2i::RealPoint ptMean = ContourHelper::getBarycenter(vectContoursBdryPointels.at(k));
160 unsigned int distance = (
unsigned int)ceil(sqrt((ptMean[0]-refPoint[0])*(ptMean[0]-refPoint[0])+
161 (ptMean[1]-refPoint[1])*(ptMean[1]-refPoint[1])));
162 if(distance<=selectDistanceMax){
163 FreemanChain<Z2i::Integer> fc (vectContoursBdryPointels.at(k));
164 std::cout << fc.x0 <<
" " << fc.y0 <<
" " << fc.chain << std::endl;
173 int main(
int argc,
char** argv )
177 std::string inputFileName;
178 std::string outputFileName {
"result.fc"};
180 double minThreshold {128};
181 double maxThreshold {255};
182 unsigned int minSize {0};
184 bool sortCnt {
false};
186 Z2i::Point selectCenter;
187 unsigned int selectDistanceMax = 0;
188 std::vector<int> cntConstraints;
189 std::vector<int> vectRangeMin, vectRangeMax, vectRange;
191 app.description(
"Extract FreemanChains from thresholded image.\n Basic example: \t img2freeman [options] --input <imageName> -min 128 -max 255 > contours.fc \n Note that if you don't specify any threshold a threshold threshold max is automatically defined from the Otsu algorithm with min=0. ");
192 app.add_option(
"-i,--input,1", inputFileName,
"input image file name (any 2D image format accepted by DGtal::GenericReader)." )
194 ->check(CLI::ExistingFile);
195 app.add_option(
"-m,--min", minThreshold,
"min image threshold value (default 128)");
196 app.add_option(
"-M,--max", maxThreshold,
"max image threshold value (default 255)");
197 app.add_flag(
"--sort", sortCnt,
"to sort the resulting freemanchain by decreasing size." );
198 app.add_option(
"-s,--minSize", minSize,
"minSize of the extracted freeman chain (default 0)" );
199 app.add_option(
"contourSelect",cntConstraints,
"Select contour according reference point and maximal distance: ex. --contourSelect X Y distanceMax" )
201 app.add_option(
"-r,--thresholdRangeMin",vectRangeMin,
"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." )
203 app.add_option(
"-R,--thresholdRangeMax",vectRangeMax,
"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." )
207 app.get_formatter()->column_width(40);
208 CLI11_PARSE(app, argc, argv);
212 bool thresholdRange=vectRangeMax.size()==3 || vectRangeMin.size()==3;
213 typedef functors::IntervalThresholder<Image::Value> Binarizer;
214 Image image = GenericReader<Image>::import( inputFileName );
217 if(cntConstraints.size()==3){
219 selectCenter[0]= cntConstraints.at(0);
220 selectCenter[1]= cntConstraints.at(1);
221 selectDistanceMax= (
unsigned int) cntConstraints.at(2);
224 int min, max, increment;
225 if(! thresholdRange){
226 min=(int)minThreshold;
227 max= (int)maxThreshold;
228 increment = (int)(maxThreshold - minThreshold);
229 if(minThreshold == 128 && maxThreshold == 255) {
231 trace.info() <<
"Min/Max threshold values not specified, set min to 0 and computing max with the otsu algorithm...";
232 max = getOtsuThreshold(image);
233 trace.info() <<
"[done] (max= " << max <<
") "<< std::endl;
237 vectRange = (vectRangeMin.size()==3) ? vectRangeMin : vectRangeMax;
239 increment=vectRange.at(1);
240 max = vectRange.at(2);
247 if(! ks.init( image.domain().lowerBound(),
248 image.domain().upperBound(),
true )){
249 trace.error() <<
"Problem in KSpace initialisation"<< std::endl;
253 if (!thresholdRange){
254 Binarizer b(min, max);
255 functors::PointFunctorPredicate<Image,Binarizer> predicate(image, b);
256 trace.info() <<
"DGtal contour extraction from thresholds ["<< min <<
"," << max <<
"]" ;
257 SurfelAdjacency<2> sAdj(
true );
258 std::vector< std::vector< Z2i::Point > > vectContoursBdryPointels;
259 Surfaces<Z2i::KSpace>::extractAllPointContours4C( vectContoursBdryPointels,
260 ks, predicate, sAdj );
262 saveSelContoursAsFC(vectContoursBdryPointels, minSize, selectCenter, selectDistanceMax, sortCnt);
264 saveAllContoursAsFc(vectContoursBdryPointels, minSize, sortCnt);
267 for(
int i=0; minThreshold+i*increment< maxThreshold; i++){
268 if(vectRangeMin.size()==3){
269 min = (int)(minThreshold+(i)*increment);
271 if(vectRangeMax.size()==3){
272 max = (int)(maxThreshold-(i)*increment);
274 Binarizer b(min, max);
275 functors::PointFunctorPredicate<Image,Binarizer> predicate(image, b);
277 trace.info() <<
"DGtal contour extraction from thresholds ["<< min <<
"," << max <<
"]" ;
278 SurfelAdjacency<2> sAdj(
true );
279 std::vector< std::vector< Z2i::Point > > vectContoursBdryPointels;
280 Surfaces<Z2i::KSpace>::extractAllPointContours4C( vectContoursBdryPointels,
281 ks, predicate, sAdj );
283 saveSelContoursAsFC(vectContoursBdryPointels, minSize,
284 selectCenter, selectDistanceMax, sortCnt);
286 saveAllContoursAsFc(vectContoursBdryPointels,
289 trace.info() <<
" [done]" << std::endl;