Vous avez reçu un message "Your GitLab account has been locked ..." ? Pas d'inquiétude : lisez cet article https://docs.gricad-pages.univ-grenoble-alpes.fr/help/unlock/

Commit 6b0737a1 authored by saubatn's avatar saubatn
Browse files

UPDATED Improved DICOM supports. Now, all images files are supported (files...

UPDATED Improved DICOM supports. Now, all images files are supported (files wich are not DICOM and containing images are ignored).
FIXED Issues on opening volumic images with only one file (DICOM image file, such as DICOMDIR). Files are now correctly sorted and opened.
UPDATED LUT is taken into account and can be adjusted on DICOM volumic images.

git-svn-id: svn+ssh://scm.forge.imag.fr/var/lib/gforge/chroot/scmrepos/svn/camitk/trunk/camitk@2005 ec899d31-69d1-42ba-9299-647d76f65fb3
parent abe03efd
......@@ -41,8 +41,6 @@
#include <gdcmScanner.h>
#include <gdcmIPPSorter.h>
using namespace camitk;
// --------------- Constructor -------------------
......@@ -58,19 +56,39 @@ DicomComponent::DicomComponent(DicomSerie* dicomSerie) throw(AbortException) : I
scanner.AddTag(serieDescriptionTag);
scanner.Scan(stdFileNames);
setName(QString(scanner.GetValue(stdFileNames.at(0).c_str(), serieDescriptionTag)));
// std::cout << "SERIE name = " << getName().toStdString() << std::endl;
// sort the files according to Patient position ect ...
gdcm::IPPSorter ippSorter;
ippSorter.SetComputeZSpacing(true);
ippSorter.SetZSpacingTolerance(0.1);
if(!ippSorter.Sort(stdFileNames))
CAMITK_ERROR("DicomSerieComponent", "DicomSerieComponent", "IPPSorter sorting failed. Try to adjust Z spacing tolerance.")
vtkSmartPointer<vtkStringArray> fileNamesSorted = vtkSmartPointer<vtkStringArray>::New();
std::vector< std::string > files = ippSorter.GetFilenames();
// std::cout << "IPP Sorter has found " << files.size() << " files" << std::endl;
// Use Image Position Patient filter (IPPSorter) to correctly sort slices according to their Z spacing
// Also deduce the actual Z spacing
std::vector< std::string > files;
double zSpacing = 0.0;
if (stdFileNames.size() > 1)
{
gdcm::IPPSorter ippSorter;
ippSorter.SetComputeZSpacing(true);
ippSorter.SetZSpacingTolerance(0.001);
if(!ippSorter.Sort(stdFileNames))
{
CAMITK_ERROR("DicomSerieComponent", "DicomSerieComponent", "IPPSorter sorting failed. Try to adjust Z spacing tolerance.")
files = stdFileNames;
zSpacing = DicomParser::getZSpacing(files);
}
else
{
files = ippSorter.GetFilenames();
zSpacing = ippSorter.GetZSpacing();
}
}
else
{
files = stdFileNames;
zSpacing = DicomParser::getZSpacing(files);
}
// convert this list as a vtkStringArray
vtkSmartPointer<vtkStringArray> fileNamesSorted = vtkSmartPointer<vtkStringArray>::New();
foreach(std::string file, files)
fileNamesSorted->InsertNextValue(file.c_str());
fileNamesSorted->InsertNextValue(file.c_str());
// get image orientation information
// we need to get the rotation matrix from tag "Direct cos angle"
......@@ -82,7 +100,10 @@ DicomComponent::DicomComponent(DicomSerie* dicomSerie) throw(AbortException) : I
// create image data corresponding to the component
imageReader = vtkGDCMImageReader::New();
imageReader->SetFileNames(fileNamesSorted);
if(fileNamesSorted->GetSize() == 1)
imageReader->SetFileName(fileNamesSorted->GetValue(0));
else
imageReader->SetFileNames(fileNamesSorted);
imageReader->Update();
vtkSmartPointer<vtkImageData> rawData = imageReader->GetOutput();
......@@ -90,17 +111,17 @@ DicomComponent::DicomComponent(DicomSerie* dicomSerie) throw(AbortException) : I
// Update Z-spacing
// vtkGDCMImageReader missses this information, see: http://gdcm.sourceforge.net/2.4/html/classvtkGDCMImageReader.html#details
// Use the value found from IPPSorter or DicomParser::GetZSpacing()
double *spacing = imageReader->GetDataSpacing();
double ippZSpacing = ippSorter.GetZSpacing();
if (ippZSpacing == 0) {
// if IPPSorter returned 0, it means that its input parameters were wrong, see: http://gdcm.sourceforge.net/2.4/html/classgdcm_1_1IPPSorter.html#aaef7af132da723719c52be5f8d3cb21d
CAMITK_WARNING("DicomSerieComponent", "DicomSerieComponent", "IPPSorter Z spacing computation failed, try to adjust the tolerance. Setting it back to 1")
ippZSpacing = 1;
}
// Update Z Spacing using a VTK pipeline
vtkImageChangeInformation *imageInfoChanger = vtkImageChangeInformation::New();
imageInfoChanger->SetInput(rawData); //translatedData);
// std::cout << "spacing found = (" << spacing[0] << ", " << spacing[1] << ", " << ippZSpacing << ")" << std::endl;
imageInfoChanger->SetOutputSpacing(spacing[0], spacing[1], ippZSpacing);
/// DEBUG
// std::cout << "spacing found = (" << spacing[0] << ", " << spacing[1] << ", " << zSpacing << ")" << std::endl;
imageInfoChanger->SetOutputSpacing(spacing[0], spacing[1], zSpacing);
imageInfoChanger->Update();
// Flip all actors in the Y axis
......@@ -123,7 +144,7 @@ DicomComponent::DicomComponent(DicomSerie* dicomSerie) throw(AbortException) : I
setImageData(image, false, orientation);
// Wait for the LUT update in CamiTK and / or support for color image
// updateLUT();
updateLUT();
}
......@@ -141,6 +162,11 @@ void DicomComponent::updateLUT() {
double range[2] = {0.0, 0.0};
imageReader->GetOutput()->GetScalarRange(range);
getLut()->SetRange(range); // we need to set up range and table values
getLut()->SetLevel((abs(range[0]) + abs(range[1])) / 2);
/// DEBUG
// std::cout << "updateLut >> Range = ( " << range[0] << ", " << range[1] << ")" << std::endl;
getLut()->SetNumberOfTableValues(abs(range[0]) + abs(range[1]));
// std::cout << "UPDATE DONE" << std::endl;
}
......@@ -152,7 +178,19 @@ camitk::ImageOrientationHelper::PossibleImageOrientations DicomComponent::readDi
gdcm::Scanner scanner;
gdcm::Tag iopTag = gdcm::Tag(0x0020, 0x0037);
scanner.AddTag(iopTag);
scanner.Scan(fileNames);
if(!scanner.Scan(fileNames)) // Definitively, scan should never failed, since DicomParser::parseDirectory() has already filter files.
CAMITK_ERROR("DicomComponent", "readDirectCosinesAngle", "Scan failed looking for tag (0x0020, 0x0037) Image Orientation Patient");
// Check value tag exists
gdcm::Scanner::TagToValue const &ttv = scanner.GetMapping(fileNames[0].c_str());
gdcm::Scanner::TagToValue::const_iterator it = ttv.find(iopTag);
if(!(it != ttv.end()))
{
CAMITK_WARNING("DicomComponent", "readDirectCosinesAngle","No tag (0x0020, 0x0037) Image Orientation Patient found on image " + fileNames[0]);
return ImageOrientationHelper::UNKNOWN;
}
// Then we know it exists
std::string value = scanner.GetValue(fileNames[0].c_str(), iopTag);
// convert the string into the appropriate couple of cosine vectors
......
......@@ -42,7 +42,7 @@ class DicomDialogEntry;
/**
* @ingroup group_cepimaging_components_dicomimage
* @ingroup group_cepimaging_components_dicom
*
* @brief
* DICOM image Component manager.
......@@ -102,7 +102,6 @@ private:
/// The different Dicom SERIE parsed
QList<DicomSerie*> serieParsed;
/// The serie dialog entries representation in the VIEW
QList<DicomDialogEntry*> serieDialogEntries;
......
......@@ -24,10 +24,12 @@
****************************************************************************/
// CamiTK includes
#include "DicomParser.h"
#include <Log.h>
// GDCM includes
#include <gdcmScanner.h>
#include <gdcmIPPSorter.h>
#include <gdcmImageReader.h>
// --------------- parseDirectory -------------------
......@@ -40,12 +42,45 @@ QList<DicomSerie*> DicomParser::parseDirectory(const QString & directory) {
dir.Load(directory.toStdString().c_str(), true);
const std::vector< std::string > & fileNames = dir.GetFilenames();
// Filter files to retrieve only DICOM files featuring an image (PixelData dataset)
// Inspired for GDCM scanner basic example
// see : http://gdcm.sourceforge.net/html/SimpleScanner_8cxx-example.html#_a7
std::vector< std::string > imageFileNames;
gdcm::Scanner dicomImageScanner;
const gdcm::Tag tagPixelData(0x7fe0, 0x0010);
dicomImageScanner.AddTag(tagPixelData);
dicomImageScanner.Scan(fileNames);
CAMITK_DEBUG("DicomParser", "parseDirectory", "Parsing files for DICOM image files");
foreach(std::string file, dicomImageScanner.GetFilenames())
{
// 1st check the file is a valid DICOM file
if(dicomImageScanner.IsKey(file.c_str()))
{
// 2nd check the dicom file is is an image file
gdcm::Scanner::TagToValue const &ttv = dicomImageScanner.GetMapping(file.c_str());
gdcm::Scanner::TagToValue::const_iterator it = ttv.find( tagPixelData );
if( it != ttv.end() )
{
CAMITK_DEBUG("DicomParser", "parseDirectory", file +" is a DICOM image file");
imageFileNames.push_back(file);
}
else
CAMITK_DEBUG("DicomParser", "parseDirectory", file +" is a DICOM file WITHOUT PixelData information");
}
else
CAMITK_DEBUG("DicomParser", "parseDirectory", file +" is not a valid DICOM file");
}
// filter files per image and STUDY
gdcm::Tag studyUIDTag = gdcm::Tag(0x0020,0x000d);
// Note : we can put an observer for load bar
gdcm::Scanner studyScanner;
studyScanner.AddTag(studyUIDTag);
studyScanner.Scan(fileNames);
/// DEBUG
studyScanner.Scan(imageFileNames);
// retrieve all the studies results
const std::set< std::string > studyValues = studyScanner.GetValues();
......@@ -65,15 +100,6 @@ QList<DicomSerie*> DicomParser::parseDirectory(const QString & directory) {
// get file associated with this serie
std::vector< std::string > serieFileNames = seriesScanner.GetAllFilenamesFromTagToValue(serieUIDTag, serieName.c_str());
// This filter aims at removing volumic images containing only a few images, for doctors TOPO for instance
// if ippsorter algorithm returns 0, it means it hasn't been able to sort the files according to their Z spacing
// It could come from a bad z spacing tolerance or the image files have no z spacing
gdcm::IPPSorter ippsorter;
ippsorter.SetComputeZSpacing(true);
ippsorter.SetZSpacingTolerance(0.01);
ippsorter.Sort(serieFileNames);
serieFileNames = ippsorter.GetFilenames();
// build a DicomSerie object corresponding to what we have found
if(serieFileNames.size() > 0) {
DicomSerie* crtSerie = new DicomSerie();
......@@ -89,8 +115,6 @@ QList<DicomSerie*> DicomParser::parseDirectory(const QString & directory) {
dicomSeries.append(crtSerie);
}
}
}
return dicomSeries;
......@@ -192,6 +216,17 @@ std::vector< std::string > DicomParser::qtListOfStringToStd(const QList<QString>
return outputFileNames;
}
// --------------- getZSpacing -------------------
double DicomParser::getZSpacing(const std::vector<std::string> & serieFileNames){
gdcm::Scanner scanner;
gdcm::Tag zSpacingTag = gdcm::Tag(0x0018, 0x0088);
scanner.AddTag(zSpacingTag);
scanner.Scan(serieFileNames);
std::string file = serieFileNames.at(0);
const char* value = scanner.GetValue(file.c_str(), zSpacingTag);
return atof(value);
}
......
......@@ -62,6 +62,13 @@ public:
* @return A list of DicomSerie, high level CamiTK object which store information of a SERIE
*/
static QList<DicomSerie*> parseDirectory(const QString & directory);
/**
* @brief Retrieve the DICOM image file Z spacing attribute (commonly known as spacing between slices)
* @param serieFileNames the input DICOM image images to retrieve the Z spacing attribute from.
* @return the Z spacing value.
*/
static double getZSpacing(const std::vector<std::string> & serieFileNames);
private:
/**
......@@ -120,8 +127,6 @@ private:
*/
static QString getStudyName(const std::vector<std::string> & serieFileNames);
};
#endif // DICOMPARSER_H
......
......@@ -105,7 +105,6 @@ private:
/// The image file names associated to this SERIE (std list, for GDCM API)
std::vector<std::string> stdFileNames;
};
#endif // DICOMSERIE_H
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment