]> Creatis software - clitk.git/blob - vv/vvToolHistogram.cxx
Add window/level lines in histogram tool
[clitk.git] / vv / vvToolHistogram.cxx
1 /*=========================================================================
2   Program:   vv                     http://www.creatis.insa-lyon.fr/rio/vv
3
4   Authors belong to:
5   - University of LYON              http://www.universite-lyon.fr/
6   - Léon Bérard cancer center       http://www.centreleonberard.fr
7   - CREATIS CNRS laboratory         http://www.creatis.insa-lyon.fr
8
9   This software is distributed WITHOUT ANY WARRANTY; without even
10   the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
11   PURPOSE.  See the copyright notices for more information.
12
13   It is distributed under dual licence
14
15   - BSD        See included LICENSE.txt file
16   - CeCILL-B   http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
17   ===========================================================================**/
18
19 #include <QFileDialog>
20 #include <QShortcut>
21
22 #include <algorithm>
23
24 // vv
25 #include "vvToolHistogram.h"
26 #include "vvProgressDialog.h"
27 #include "vvSlicerManager.h"
28 #include "vvSlicer.h"
29 #include "vvToolInputSelectorWidget.h"
30
31 // vtk
32 #include <vtkAxis.h>
33 #include <vtkImageActor.h>
34 #include <vtkCamera.h>
35 #include <vtkImageClip.h>
36 #include <vtkRenderWindow.h>
37 #include <vtkChartXY.h>
38 #include <vtkPlot.h>
39 #include <vtkRendererCollection.h>
40 #include <vtkRenderer.h>
41
42 #include <vtkLine.h>
43 #include <vtkCellArray.h>
44 #include <vtkCellData.h>
45 #include <vtkPolyDataMapper.h>
46 #include <vtkProperty.h>
47 #include <vtkBox.h>
48 #include <vtkInformation.h>
49
50 #ifdef Q_OS_OSX
51 # include "vvOSXHelper.h"
52 #endif
53
54 //------------------------------------------------------------------------------
55 // Create the tool and automagically (I like this word) insert it in
56 // the main window menu.
57 ADD_TOOL(vvToolHistogram);
58 //------------------------------------------------------------------------------
59
60
61 //------------------------------------------------------------------------------
62 void vvToolHistogram::Initialize()
63
64   SetToolName("Histogram");
65   SetToolMenuName("Intensity Histogram");
66   SetToolIconFilename(":/common/icons/histogram.png");
67   SetToolTip("Display the histogram of the image.");
68   SetToolExperimental(false);
69 }
70 //------------------------------------------------------------------------------
71
72
73 //------------------------------------------------------------------------------
74 vvToolHistogram::vvToolHistogram(vvMainWindowBase * parent, Qt::WindowFlags f)
75   :vvToolWidgetBase(parent,f),
76    vvToolBase<vvToolHistogram>(parent),
77    Ui::vvToolHistogram()
78
79   // GUI Initialization
80   Ui_vvToolHistogram::setupUi(mToolWidget);
81
82   // Connect signals & slots
83   connect(mSaveHistogramButton, SIGNAL(clicked()), this, SLOT(SaveAs()));
84
85   // Initialize some widget
86   HistogramWidget->hide();
87
88   mView = vtkSmartPointer<vtkContextView>::New();
89   vtkSmartPointer<vtkChartXY> chart = vtkSmartPointer<vtkChartXY>::New();
90   chart->SetAutoSize(false);
91   chart->SetRenderEmpty(true);
92   mView->GetScene()->AddItem(chart);
93   this->HistogramWidget->GetRenderWindow()->GetRenderers()->RemoveAllItems();
94   this->HistogramWidget->GetRenderWindow()->AddRenderer(mView->GetRenderer());
95   HistogramWidget->show();
96
97 #ifdef Q_OS_OSX
98   disableGLHiDPI(HistogramWidget->winId());
99 #endif
100
101   // Main filter
102   mFilter = clitk::HistogramImageGenericFilter::New();
103
104   // Set how many inputs are needed for this tool
105   AddInputSelector("Select one image", mFilter);
106 }
107 //------------------------------------------------------------------------------
108
109
110 //------------------------------------------------------------------------------
111 vvToolHistogram::~vvToolHistogram()
112
113 }
114 //------------------------------------------------------------------------------
115
116
117 //------------------------------------------------------------------------------
118 void vvToolHistogram::computeHistogram()
119 {
120     if (!mCurrentSlicerManager) close();
121     QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
122     GetArgsInfoFromGUI();
123     HistogramWidget->hide();
124
125     // Main filter
126     mFilter->SetInputVVImage(mCurrentImage);
127     mFilter->SetArgsInfo(mArgsInfo);
128     mFilter->Update();
129
130     //Creation of the XY chart
131     vtkSmartPointer<vtkTable> table = vtkSmartPointer<vtkTable>::New();
132     vtkSmartPointer<vtkFloatArray> arrX = vtkSmartPointer<vtkFloatArray>::New();
133     vtkSmartPointer<vtkFloatArray> arrY = vtkSmartPointer<vtkFloatArray>::New();
134     arrX = mFilter->GetArrayX();
135     arrY = mFilter->GetArrayY();
136     arrX->SetName("Intensity");
137     arrY->SetName("#Voxels");
138
139     table->AddColumn(arrX);
140     table->AddColumn(arrY);
141
142     mView->GetRenderer()->SetBackground(1.0, 1.0, 1.0);
143
144     vtkSmartPointer<vtkChartXY> chart = vtkSmartPointer<vtkChartXY>::New();
145     chart->SetAutoSize(true);
146     mView->GetScene()->ClearItems();
147     mView->GetScene()->AddItem(chart);
148     vtkPlot *line = chart->AddPlot(vtkChart::LINE);
149 #if VTK_MAJOR_VERSION <= 5
150     line->SetInput(table, 0, 1);
151 #else
152     line->SetInputData(table, 0, 1);
153 #endif
154     line->SetColor(0, 255, 0, 255);
155     line->SetWidth(1.0);
156
157     //Upper and Lower lines for window/level
158     vtkSmartPointer<vtkTable> tableWindowLevel = vtkSmartPointer<vtkTable>::New();
159     vtkSmartPointer<vtkFloatArray> arrXUpperWindowLevel = vtkSmartPointer<vtkFloatArray>::New();
160     vtkSmartPointer<vtkFloatArray> arrXLowerWindowLevel = vtkSmartPointer<vtkFloatArray>::New();
161     vtkSmartPointer<vtkFloatArray> arrYWindowLevel = vtkSmartPointer<vtkFloatArray>::New();
162     arrXUpperWindowLevel->InsertNextTuple1(mMaxWindowLevel);
163     arrXUpperWindowLevel->InsertNextTuple1(mMaxWindowLevel);
164     arrXLowerWindowLevel->InsertNextTuple1(mMinWindowLevel);
165     arrXLowerWindowLevel->InsertNextTuple1(mMinWindowLevel);
166     arrYWindowLevel->InsertNextTuple1(0.0);
167     arrYWindowLevel->InsertNextTuple1(arrY->GetMaxNorm());
168     arrXUpperWindowLevel->SetName("IntensityUp");
169     arrXLowerWindowLevel->SetName("IntensityLow");
170     arrYWindowLevel->SetName("#Voxels");
171     tableWindowLevel->AddColumn(arrXUpperWindowLevel);
172     tableWindowLevel->AddColumn(arrXLowerWindowLevel);
173     tableWindowLevel->AddColumn(arrYWindowLevel);
174     vtkPlot *upperWindowLine = chart->AddPlot(vtkChart::LINE);
175     vtkPlot *lowerWindowLine = chart->AddPlot(vtkChart::LINE);
176 #if VTK_MAJOR_VERSION <= 5
177     upperWindowLine->SetInput(tableWindowLevel, 0, 2);
178     lowerWindowLine->SetInput(tableWindowLevel, 1, 2);
179 #else
180     upperWindowLine->SetInputData(tableWindowLevel, 0, 2);
181     lowerWindowLine->SetInputData(tableWindowLevel, 1, 2);
182 #endif
183     upperWindowLine->SetColor(255, 0, 0, 255);
184     lowerWindowLine->SetColor(255, 0, 0, 255);
185     upperWindowLine->SetWidth(1.0);
186     lowerWindowLine->SetWidth(1.0);
187
188     chart->GetAxis(vtkAxis::LEFT)->SetTitle("#Voxels");
189     chart->GetAxis(vtkAxis::BOTTOM)->SetTitle("Intensity");
190
191     this->HistogramWidget->GetRenderWindow()->GetRenderers()->RemoveAllItems();
192     this->HistogramWidget->GetRenderWindow()->AddRenderer(mView->GetRenderer());
193     HistogramWidget->show();
194
195     //mView->GetInteractor()->Start();
196
197     QApplication::restoreOverrideCursor();
198 }
199 //------------------------------------------------------------------------------
200
201 //------------------------------------------------------------------------------
202 void vvToolHistogram::changeWindowLevel()
203 {
204   vtkChartXY* chart = vtkChartXY::New();
205   chart = static_cast<vtkChartXY*>(mView->GetScene()->GetItem(0));
206   vtkFloatArray* upperArray = vtkFloatArray::New();
207   upperArray = static_cast<vtkFloatArray*>(chart->GetPlot(1)->GetInput()->GetColumn(0));
208   upperArray->SetTuple1(0, mMaxWindowLevel);
209   upperArray->SetTuple1(1, mMaxWindowLevel);
210   vtkFloatArray* lowerArray = vtkFloatArray::New();
211   lowerArray = static_cast<vtkFloatArray*>(chart->GetPlot(2)->GetInput()->GetColumn(1));
212   lowerArray->SetTuple1(0, mMinWindowLevel);
213   lowerArray->SetTuple1(1, mMinWindowLevel);
214 }
215 //------------------------------------------------------------------------------
216
217
218 //------------------------------------------------------------------------------
219 void vvToolHistogram::windowLevelChanged()
220 {
221   computeMinMax();
222   changeWindowLevel();
223 }
224 //------------------------------------------------------------------------------
225
226
227 //------------------------------------------------------------------------------
228 void vvToolHistogram::RemoveVTKObjects()
229
230   if (mCurrentSlicerManager)
231   {
232     connect(mCurrentSlicerManager, SIGNAL(callAddLandmark(float,float,float,float)), mCurrentSlicerManager, SLOT(AddLandmark(float,float,float,float)));
233
234     mCurrentSlicerManager->Render();
235   }
236 }
237 //------------------------------------------------------------------------------
238
239
240 //------------------------------------------------------------------------------
241 bool vvToolHistogram::close()
242
243   //RemoveVTKObjects();
244
245   return vvToolWidgetBase::close();
246 }
247 //------------------------------------------------------------------------------
248
249
250 //------------------------------------------------------------------------------
251 void vvToolHistogram::closeEvent(QCloseEvent *event)
252
253   RemoveVTKObjects();
254   event->accept();
255 }
256 //------------------------------------------------------------------------------
257
258
259 //------------------------------------------------------------------------------
260 void vvToolHistogram::reject()
261
262   // DD("vvToolHistogram::reject");
263   RemoveVTKObjects();
264   return vvToolWidgetBase::reject();
265 }
266 //------------------------------------------------------------------------------
267
268
269 //------------------------------------------------------------------------------
270 void vvToolHistogram::InputIsSelected(vvSlicerManager * m)
271
272   mCurrentSlicerManager = m;
273
274   mSaveHistogramButton->setEnabled(true);
275   mTextFileName = "Histogram.txt";
276
277   //Compute Min & Max for Window/Level
278   computeMinMax();
279
280   computeHistogram();
281
282   disconnect(mCurrentSlicerManager, SIGNAL(callAddLandmark(float,float,float,float)), mCurrentSlicerManager, SLOT(AddLandmark(float,float,float,float)));
283 }
284 //------------------------------------------------------------------------------
285
286
287 //------------------------------------------------------------------------------
288 void vvToolHistogram::computeMinMax()
289 {
290   mMinWindowLevel = mCurrentSlicerManager->GetColorLevel() - mCurrentSlicerManager->GetColorWindow()/2.0;
291   mMaxWindowLevel = mCurrentSlicerManager->GetColorLevel() + mCurrentSlicerManager->GetColorWindow()/2.0;
292 }
293 //------------------------------------------------------------------------------
294
295
296 //------------------------------------------------------------------------------
297 void vvToolHistogram::computeWindowLevel()
298 {
299   double window = mMaxWindowLevel - mMinWindowLevel;
300   double level = (mMaxWindowLevel + mMinWindowLevel)/2.0;
301 }
302 //------------------------------------------------------------------------------
303
304
305 //------------------------------------------------------------------------------
306 void vvToolHistogram::GetArgsInfoFromGUI()
307
308
309   /* //KEEP THIS FOR READING GGO FROM FILE
310      int argc=1;
311      std::string a = "toto";
312      char * const* argv = new char*;
313      //a.c_str();
314      struct cmdline_parser_params p;
315      p.check_required = 0;
316      int good = cmdline_parser_ext(argc, argv, &args_info, &p);
317      DD(good);
318   */
319   cmdline_parser_clitkHistogramImage_init(&mArgsInfo); // Initialisation to default
320
321   mArgsInfo.verbose_flag = false;
322
323   // Required (even if not used)
324   mArgsInfo.input_given = 0;
325   mArgsInfo.output_given = 0;
326
327   mArgsInfo.input_arg = new char;
328   mArgsInfo.output_arg = new char;
329
330 }
331 //------------------------------------------------------------------------------
332
333
334 //------------------------------------------------------------------------------
335 void vvToolHistogram::apply()
336
337   close();
338 }
339 //------------------------------------------------------------------------------
340
341
342 //------------------------------------------------------------------------------
343 void vvToolHistogram::SaveAs()
344
345   QStringList OutputListeFormat;
346   OutputListeFormat.clear();
347   OutputListeFormat.push_back(".txt");
348   
349   QString Extensions = "AllFiles(*.*)";
350   for (int i = 0; i < OutputListeFormat.count(); i++) {
351     Extensions += ";;Text File ( *";
352     Extensions += OutputListeFormat[i];
353     Extensions += ")";
354   }
355   QString fileName = QFileDialog::getSaveFileName(this, tr("Save As"), mTextFileName.c_str(), Extensions);
356   if (!fileName.isEmpty()) {
357     std::string fileformat = itksys::SystemTools::GetFilenameLastExtension(fileName.toStdString());
358     QString fileQFormat = fileformat.c_str();
359     if (OutputListeFormat.contains(fileformat.c_str()) || fileQFormat.isEmpty()) {
360         QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
361         std::string action = "Saving";
362         vvProgressDialog progress("Saving "+fileName.toStdString());
363         qApp->processEvents();
364         
365         if (!mCurrentSlicerManager) {
366             close();
367             return;
368         }
369
370         // Output
371         mTextFileName = fileName.toStdString();
372         if (fileQFormat.isEmpty())
373             mTextFileName += ".txt";
374         ofstream fileOpen(mTextFileName.c_str(), std::ofstream::trunc);
375   
376         if(!fileOpen) {
377             cerr << "Error during saving" << endl;
378             QApplication::restoreOverrideCursor();
379             close();
380             return;
381         }
382         
383         vtkSmartPointer<vtkFloatArray> arrX = vtkSmartPointer<vtkFloatArray>::New();
384         vtkSmartPointer<vtkFloatArray> arrY = vtkSmartPointer<vtkFloatArray>::New();
385         vtkSmartPointer<vtkFloatArray> coords = vtkSmartPointer<vtkFloatArray>::New();
386         arrX = mFilter->GetArrayX();
387         arrY = mFilter->GetArrayY();
388         int i(0);
389         fileOpen << "Value represents the number of voxels around the corresponding intensity (by default the windows size around intensity is log(range))" << endl;
390         fileOpen << "Intensity" << "\t" << "Value" << endl;
391    
392         while (i<arrX->GetNumberOfTuples()) {
393             fileOpen << arrX->GetTuple(i)[0] << "\t" << arrY->GetTuple(i)[0] << endl;
394             ++i;
395         }
396
397         fileOpen.close();
398         QApplication::restoreOverrideCursor();
399     } else {
400       QString error = fileformat.c_str();
401       error += " format unknown !!!\n";
402       QMessageBox::information(this,tr("Saving Problem"),error);
403       SaveAs();
404     }
405   }
406 }
407 //------------------------------------------------------------------------------