DGtalTools  1.3.beta
3dVolViewer.cpp
1 
27 #include <iostream>
29 
30 #include "DGtal/base/Common.h"
31 #include "DGtal/base/BasicFunctors.h"
32 #include "DGtal/helpers/StdDefs.h"
33 #include "DGtal/io/readers/GenericReader.h"
34 #include "DGtal/io/viewers/Viewer3D.h"
35 #include "DGtal/io/DrawWithDisplay3DModifier.h"
36 #include "DGtal/io/readers/PointListReader.h"
37 #include "DGtal/io/readers/MeshReader.h"
38 
39 #include "DGtal/io/Color.h"
40 #include "DGtal/io/colormaps/GradientColorMap.h"
41 #include "DGtal/images/ImageSelector.h"
42 
43 #include "CLI11.hpp"
44 
45 using namespace std;
46 using namespace DGtal;
47 using namespace Z3i;
48 
49 
103 template < typename Space = DGtal::Z3i::Space, typename KSpace = DGtal::Z3i::KSpace>
104 struct ViewerSnap: DGtal::Viewer3D <Space, KSpace>
105 {
106 
107  ViewerSnap(bool saveSnap): Viewer3D<Space, KSpace>(), mySaveSnap(saveSnap){
108  };
109 
110  virtual void
111  init(){
113  if(mySaveSnap){
114  QObject::connect(this, SIGNAL(drawFinished(bool)), this, SLOT(saveSnapshot(bool)));
115  }
116  };
117  bool mySaveSnap;
118 };
119 
120 typedef ViewerSnap<> Viewer;
121 
122 
123 
124 // call back function to display voxel coordinates
125 template<typename TImage>
126 int
127 displayCoordsCallBack( void* viewer, int name, void* data )
128 {
129  TImage *image = (TImage *) data;
130  std::stringstream ss;
132  // Check needed since simetimes the point appears outside (only in non debug mode).
133  if (image->domain().isInside(p)){
134  ss << "Selected intensity: " << (*image)(p) << "p " << p[0] << " "<< p[1] << " " << p[2] ;
135  ((Viewer *) viewer)->displayMessage(QString(ss.str().c_str()), 100000);
136  }
137  return 0;
138 }
139 
140 
141 template <typename TImage>
142 void
143 processDisplay(ViewerSnap<> &viewer, TImage &image,
144  const typename TImage::Value &thresholdMin,
145  const typename TImage::Value &thresholdMax,
146  unsigned int numDisplayedMax,
147  unsigned int transparency,
148  bool interDisplay=false)
149 {
150  Domain domain = image.domain();
151  GradientColorMap<typename TImage::Value> gradient( thresholdMin, thresholdMax);
152  unsigned int numDisplayed = 0;
153  gradient.addColor(Color::Blue);
154  gradient.addColor(Color::Green);
155  gradient.addColor(Color::Yellow);
156  gradient.addColor(Color::Red);
157  for(Domain::ConstIterator it = domain.begin(), itend=domain.end(); it!=itend; ++it){
158  typename TImage::Value val= image( (*it) );
159  if(numDisplayed > numDisplayedMax)
160  break;
161  Color c= gradient(val);
162  if(val<=thresholdMax && val >=thresholdMin)
163  {
164  viewer << CustomColors3D(Color((float)(c.red()), (float)(c.green()),(float)(c.blue()), transparency),
165  Color((float)(c.red()), (float)(c.green()),(float)(c.blue()), transparency));
166  if (interDisplay)
167  {
168  auto p = *it;
170  viewer << SetName3D( index ) ;
171  }
172  viewer << *it;
173  numDisplayed++;
174  }
175  }
176  if (interDisplay){
177  viewer << SetSelectCallback3D(displayCoordsCallBack<TImage>,
178  &image );
179  }
180 }
181 
182 
183 
184 
185 int main( int argc, char** argv )
186 {
187  // parse command line using CLI ----------------------------------------------
188  CLI::App app;
189  app.description("Display volume file as a voxel set by using QGLviewer. \n Example: \n \t 3dVolViewer $DGtal/examples/samples/lobster.vol -m 60 -t 10");
190  std::string inputFileName;
191  DGtal::int64_t rescaleInputMin {0};
192  DGtal::int64_t rescaleInputMax {255};
193  double thresholdMin {0};
194  double thresholdMax {255};
195  unsigned int transparency {255};
196  unsigned int numDisplayedMax {500000};
197  std::string displayMesh;
198  std::string snapShotFile;
199  std::vector<unsigned int> colorMesh;
200  string inputType {""};
201  bool interactiveDisplayVoxCoords {false};
202 
203  app.add_option("-i,--input,1", inputFileName, "vol file (.vol, .longvol .p3d, .pgm3d and if WITH_ITK is selected: dicom, dcm, mha, mhd). For longvol, dicom, dcm, mha or mhd formats, the input values are linearly scaled between 0 and 255." )
204  ->required()
205  ->check(CLI::ExistingFile);
206 #ifdef WITH_ITK
207  app.add_option("--inputType", inputType, "to specify the input image type (int or double).")
208  -> check(CLI::IsMember({"int", "double"}));
209 #endif
210  app.add_option("--thresholdMin,-m", thresholdMin, "threshold min (excluded) to define binary shape.", true);
211  app.add_option("--thresholdMax,-M", thresholdMax, "threshold max (included) to define binary shape.", true);
212  app.add_option("--rescaleInputMin", rescaleInputMin, "min value used to rescale the input intensity (to avoid basic cast into 8 bits image).", true);
213  app.add_option("--rescaleInputMax", rescaleInputMax, "max value used to rescale the input intensity (to avoid basic cast into 8 bits image).", true);
214  app.add_option("--numMaxVoxel,-n", numDisplayedMax, "set the maximal voxel number to be displayed.");
215  app.add_option("--displayMesh", displayMesh, "display a Mesh given in OFF or OFS format.");
216  app.add_option("--colorMesh", colorMesh, "set the color of Mesh (given from displayMesh option) : r g b a ")
217  ->expected(4);
218  app.add_flag("--doSnapShotAndExit,-d",snapShotFile, "save display snapshot into file. Notes that the camera setting is set by default according the last saved configuration (use SHIFT+Key_M to save current camera setting in the Viewer3D). If the camera setting was not saved it will use the default camera setting." );
219  app.add_option("--transparency,-t", transparency, "change the defaukt transparency", true);
220  app.add_flag("--interactiveDisplayVoxCoords,-c", interactiveDisplayVoxCoords, " by using this option the coordinates can be displayed after selection (shift+left click on voxel).");
221  app.get_formatter()->column_width(40);
222  CLI11_PARSE(app, argc, argv);
223  // END parse command line using CLI ----------------------------------------------
224 
225  QApplication application(argc,argv);
226 
227  Viewer viewer(snapShotFile != "");
228  if(snapShotFile != ""){
229  viewer.setSnapshotFileName(QString(snapShotFile.c_str()));
230  }
231  viewer.setWindowTitle("simple Volume Viewer");
232  viewer.show();
236 
237  string extension = inputFileName.substr(inputFileName.find_last_of(".") + 1);
238 
239  std::vector<double> vectValD;
240  std::vector<int> vectValI;
241  std::vector<unsigned char> vectValUC;
242  // Image of different types are pre constructed here else it will be deleted after the type selection
243  // (and it is used in display callback)
244  Z3i::Domain d;
245  Image3D_D imageD = Image3D_D(d);
246  Image3D_I imageI = Image3D_I(d);
247  Image image = Image(d);
248 
249  if(extension != "sdp")
250  {
251  unsigned int numDisplayed=0;
252 
253 #ifdef WITH_ITK
254  if (inputType=="double")
255  {
256  imageD = DGtal::GenericReader<Image3D_D>::import(inputFileName);
257  trace.info() << "[done]"<< std::endl;
258  trace.info() << "Image loaded: D "<<imageD<< std::endl;
259  processDisplay(viewer, imageD, thresholdMin, thresholdMax, numDisplayedMax, transparency,
260  interactiveDisplayVoxCoords);
261  }
262  else if (inputType=="int")
263  {
264  imageI= DGtal::GenericReader<Image3D_I>::import(inputFileName);
265  trace.info() << "Image loaded: "<<image<< std::endl;
266  processDisplay(viewer, imageI, (int)thresholdMin, (int)thresholdMax, numDisplayedMax, transparency,
267  interactiveDisplayVoxCoords);
268  } else {
270  image = GenericReader< Image >::importWithValueFunctor( inputFileName,RescalFCT(rescaleInputMin,
271  rescaleInputMax,
272  0, 255) );
273  trace.info() << "Image loaded: "<<image<< std::endl;
274  processDisplay(viewer, image, thresholdMin, thresholdMax, numDisplayedMax, transparency,
275  interactiveDisplayVoxCoords);
276  }
277 #else
279  image = GenericReader< Image >::importWithValueFunctor( inputFileName,RescalFCT(rescaleInputMin,
280  rescaleInputMax,
281  0, 255) );
282  trace.info() << "Image loaded: "<<image<< std::endl;
283  processDisplay(viewer, image, thresholdMin, thresholdMax, numDisplayedMax, transparency,
284  interactiveDisplayVoxCoords);
285 #endif
286  }
287  else if(extension=="sdp")
288  {
289  vector<Z3i::RealPoint> vectVoxels = PointListReader<Z3i::RealPoint>::getPointsFromFile(inputFileName);
290  for(unsigned int i=0;i< vectVoxels.size(); i++){
291  viewer << Z3i::Point(vectVoxels.at(i), functors::Round<>());
292  }
293  }
294  if(displayMesh != "")
295  {
296  if(colorMesh.size() != 0)
297  {
298  Color c(colorMesh[0], colorMesh[1], colorMesh[2], colorMesh[3]);
299  viewer.setFillColor(c);
300  }
301 
302  DGtal::Mesh<Z3i::RealPoint> aMesh(colorMesh.size() == 0);
303  MeshReader<Z3i::RealPoint>::importOFFFile(displayMesh, aMesh);
304  viewer << aMesh;
305  }
306 
307  viewer << Viewer3D<>::updateDisplay;
308  if(snapShotFile != "")
309  {
310  // Appy cleaning just save the last snap
311  if(!viewer.restoreStateFromFile())
312  {
313  viewer.update();
314  }
315  std::string extension = snapShotFile.substr(snapShotFile.find_last_of(".") + 1);
316  std::string basename = snapShotFile.substr(0, snapShotFile.find_last_of("."));
317  for(int i=0; i< viewer.snapshotCounter()-1; i++){
318  std::stringstream s;
319  s << basename << "-"<< setfill('0') << setw(4)<< i << "." << extension;
320  trace.info() << "erase temp file: " << s.str() << std::endl;
321  remove(s.str().c_str());
322  }
323  std::stringstream s;
324  s << basename << "-"<< setfill('0') << setw(4)<< viewer.snapshotCounter()-1 << "." << extension;
325  rename(s.str().c_str(), snapShotFile.c_str());
326  return 0;
327  }
328  return application.exec();
329 }
STL namespace.
int main(int argc, char **argv)
static TContainer import(const std::string &filename, std::vector< unsigned int > dimSpace=std::vector< unsigned int >())
Trace trace(traceWriterTerm)
std::ostream & info()
void green(const unsigned char aGreenValue)
void red(const unsigned char aRedValue)
boost::int64_t int64_t
virtual void init()
typename Self::Domain Domain
void blue(const unsigned char aBlueValue)