使用ITK及VTK读取DICOM图像序列,并绘制图像统计直方图。
注意事项及实现思路:
2. 使用ITK读取数据后,将统计结果存入一维数组中,使用VTK的vtkBarChartActor类绘制直方图;
3. 使用vtkBarChartActor前需要将数组转换成vtkIntArray、vtkDataObject类型。
绘制结果如图所示:
代码:
#include "vtkDICOMImageReader.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkRenderer.h"
#include "vtkRenderWindow.h"
#include "vtkMarchingCubes.h"
#include "vtkStripper.h"
#include "vtkActor.h"
#include "vtkPolyDataMapper.h"
#include "vtkProperty.h"
#include "vtkCamera.h"
#include "vtkBoxWidget.h"
#include "vtkSmartPointer.h"
#include "vtkTriangleFilter.h"
#include "vtkMassProperties.h"
#include "vtkSmoothPolyDataFilter.h"
#include "vtkPolyDataNormals.h"
#include "vtkContourFilter.h"
#include "vtkRecursiveDividingCubes.h"
#include "vtkSTLWriter.h"
#include "vtkStringArray.h"
#include <vtkDataObject.h>
#include <vtkFieldData.h>
#include <vtkImageAccumulate.h>
#include <vtkImageData.h>
#include <vtkIntArray.h>
#include <vtkBarChartActor.h>
#include <vtkProperty2D.h>
#include <vtkTextProperty.h>
#include <vtkLegendBoxActor.h>
#include <vtkImageActor.h>
#include "itkGDCMImageIO.h"
#include "itkGDCMSeriesFileNames.h"
#include "itkImageSeriesReader.h"
#include "itkImageSeriesWriter.h"
#include <itkImageToVTKImageFilter.h>
#include "itkMedianImageFilter.h"
#include "itkNumericSeriesFileNames.h"
using namespace std;
#define ONE_FRAME 1;
#define THREE_DIMENSION 0;
using PixelType = int;
#if THREE_DIMENSION
constexpr unsigned int Dimension = 3;
#endif
#if !THREE_DIMENSION
constexpr unsigned int Dimension = 2;
#endif
using ImageType = itk::Image<PixelType, Dimension>;
using ImageType2D = itk::Image<PixelType, 2>;
using ReaderType = itk::ImageSeriesReader<ImageType>;
using ReaderType2D = itk::ImageFileReader<ImageType2D>;
int Histgram()
{
using ImageIOType = itk::GDCMImageIO;
using NamesGeneratorType = itk::GDCMSeriesFileNames;
ImageIOType::Pointer gdcmIO = ImageIOType::New();
ReaderType::Pointer reader = ReaderType::New();
reader->SetImageIO(gdcmIO);
#if THREE_DIMENSION
string directoryName = "D:\\input";
NamesGeneratorType::Pointer namesGenerator = NamesGeneratorType::New();
namesGenerator->SetInputDirectory(directoryName);
const ReaderType::FileNamesContainer& filenames =
namesGenerator->GetInputFileNames();
std::size_t numberOfFileNames = filenames.size();
std::cout << numberOfFileNames << std::endl;
for (unsigned int fni = 0; fni < numberOfFileNames; ++fni)
{
std::cout << "filename # " << fni << " = ";
std::cout << filenames[fni] << std::endl;
}
reader->SetFileNames(filenames);
#endif
#
#if !THREE_DIMENSION
reader->SetFileName("D:\\file.dcm");
#endif
try
{
reader->Update();
}
catch (const itk::ExceptionObject& e)
{
std::cerr << "exception in file reader " << std::endl;
std::cerr << e << std::endl;
return EXIT_FAILURE;
}
using MedianFilterType = itk::MedianImageFilter<ImageType, ImageType>;
MedianFilterType::Pointer filter = MedianFilterType::New();
ImageType::SizeType indexRadius;
indexRadius[0] = 2;
indexRadius[1] = 2;
#if THREE_DIMENSION
indexRadius[2] = 1;
#endif
filter->SetRadius(indexRadius);
filter->SetInput(reader->GetOutput());
filter->Update();
int x = reader->GetOutput()->GetBufferedRegion().GetSize()[0];
int y = reader->GetOutput()->GetBufferedRegion().GetSize()[1];
#if THREE_DIMENSION
int z = reader->GetOutput()->GetBufferedRegion().GetSize()[2];
#endif
int max = 0;
int min = 0;
for (int i = 1; i < x; i++) {
for (int j = 1; j < y; j++) {
#if THREE_DIMENSION
for (int k = 1; k < z; k++) {
#endif
ImageType::IndexType id;
id[0] = i;
id[1] = j;
#if THREE_DIMENSION
id[2] = k;
#endif
ImageType::PixelType p = filter->GetOutput()->GetPixel(id);
if (p > max) {
max = p;
}
else if (p <= min) {
min = p;
}
#if THREE_DIMENSION
}
#endif
}
}
cout << "max is " << max << " min is " << min << endl;
int* hist = new int[max + 1]{0};
for (int i = 1; i < x; i++) {
for (int j = 1; j < y; j++) {
#if THREE_DIMENSION
for (int k = 1; k < z; k++) {
#endif
ImageType::IndexType id;
id[0] = i;
id[1] = j;
#if THREE_DIMENSION
id[2] = k;
#endif
ImageType::PixelType p = filter->GetOutput()->GetPixel(id);
if (p <= 0) {
continue;
}
hist[p]++;
#if THREE_DIMENSION
}
#endif
}
}
#if !THREE_DIMENSION
typedef itk::ImageToVTKImageFilter<ImageType> ConnectorType;
ConnectorType::Pointer originalConnector = ConnectorType::New();
originalConnector->SetInput(filter->GetOutput());
originalConnector->Update();
#endif
int bins = max - 0;
int comps = 1;
vtkSmartPointer<vtkIntArray> frequencies =
vtkSmartPointer<vtkIntArray>::New();
frequencies->SetNumberOfComponents(1);
frequencies->SetArray(hist, max /4, 1);
vtkSmartPointer<vtkDataObject> dataObject =
vtkSmartPointer<vtkDataObject>::New();
dataObject->GetFieldData()->AddArray(frequencies);
vtkSmartPointer<vtkBarChartActor> barChart =
vtkSmartPointer<vtkBarChartActor>::New();
barChart->SetInput(dataObject);
barChart->SetTitle("Histogram");
barChart->GetPositionCoordinate()->SetValue(0.1, 0.1, 0.0);
barChart->GetPosition2Coordinate()->SetValue(0.9, 0.9, 0.0);
barChart->GetProperty()->SetColor(0, 0, 0);
barChart->GetTitleTextProperty()->SetColor(0, 0, 0);
barChart->GetLabelTextProperty()->SetColor(0, 0, 0);
barChart->GetLegendActor()->SetNumberOfEntries(dataObject->GetFieldData()->GetArray(0)->GetNumberOfTuples());
barChart->LabelVisibilityOff();
double colors[3][3] = {
{ 1, 0, 0 },
{ 0, 1, 0 },
{ 0, 0, 1 } };
int count = 0;
for (int i = 0; i < bins; ++i)
{
for (int j = 0; j < comps; ++j)
{
barChart->SetBarColor(count++, colors[j]);
}
}
double barView[4] = { 0.0, 0.0, 1.0, 1.0 };
vtkSmartPointer<vtkRenderer> barRender =
vtkSmartPointer<vtkRenderer>::New();
barRender->SetViewport(barView);
barRender->AddActor(barChart);
barRender->SetBackground(1.0, 1.0, 1.0);
vtkSmartPointer<vtkRenderWindow> renderWindow =
vtkSmartPointer<vtkRenderWindow>::New();
renderWindow->AddRenderer(barRender);
renderWindow->SetSize(640*3, 320*3);
renderWindow->Render();
renderWindow->SetWindowName("Gray-Image Histogram");
vtkSmartPointer<vtkRenderWindowInteractor> interactor =
vtkSmartPointer<vtkRenderWindowInteractor>::New();
interactor->SetRenderWindow(renderWindow);
interactor->Initialize();
interactor->Start();
return 0;
}