|
a |
|
b/vector_region_growing.cxx |
|
|
1 |
#include <iostream> |
|
|
2 |
#include <string> |
|
|
3 |
#include "stdlib.h" |
|
|
4 |
#include <math.h> |
|
|
5 |
#include <unordered_set> |
|
|
6 |
|
|
|
7 |
#include "itkImageRegionIterator.h" |
|
|
8 |
#include "itkImageRegionConstIterator.h" |
|
|
9 |
#include "itkImageRegionIteratorWithIndex.h" |
|
|
10 |
#include "itkHessianRecursiveGaussianImageFilter.h" |
|
|
11 |
#include "itkCastImageFilter.h" |
|
|
12 |
#include "itkImageFileReader.h" |
|
|
13 |
#include "itkImageFileWriter.h" |
|
|
14 |
#include "itkImportImageFilter.h" |
|
|
15 |
#include "itkMedianImageFilter.h" |
|
|
16 |
|
|
|
17 |
const unsigned short dimension = 3; |
|
|
18 |
typedef int VoxelType; |
|
|
19 |
typedef float outVoxelType; |
|
|
20 |
typedef itk::Image<VoxelType, dimension> InputImageType; |
|
|
21 |
typedef itk::Image<outVoxelType, dimension> OutputImageType; |
|
|
22 |
typedef itk::Point< float, InputImageType::ImageDimension > PointType; |
|
|
23 |
|
|
|
24 |
typedef float HessianVoxelType; |
|
|
25 |
typedef itk::Image<HessianVoxelType, dimension> HessianInnerImageType; |
|
|
26 |
typedef itk::CastImageFilter<InputImageType, HessianInnerImageType> CastFilterType; |
|
|
27 |
|
|
|
28 |
typedef itk::HessianRecursiveGaussianImageFilter<HessianInnerImageType> HFilterType; |
|
|
29 |
typedef itk::Vector<HessianVoxelType, dimension> VecVoxType; |
|
|
30 |
typedef itk::Matrix<HessianVoxelType, dimension, dimension> MatVoxType; |
|
|
31 |
typedef itk::Image<VecVoxType, dimension> VecEigHImageType; |
|
|
32 |
typedef itk::Image<MatVoxType, dimension> MatEigHImageType; |
|
|
33 |
|
|
|
34 |
typedef itk::MedianImageFilter<OutputImageType, OutputImageType > MedianImageFilterType; |
|
|
35 |
typedef itk::ImportImageFilter< outVoxelType, dimension > ImportFilterType; |
|
|
36 |
typedef itk::ImageRegionIterator<OutputImageType> OutputImageIterType; |
|
|
37 |
typedef itk::ImageRegionIterator<VecEigHImageType> OutputIterType; |
|
|
38 |
typedef itk::ImageRegionIterator<InputImageType> InputImageIterType; |
|
|
39 |
typedef itk::SymmetricEigenAnalysis<MatVoxType, VecVoxType, MatVoxType> EigValAnalysisType; |
|
|
40 |
typedef MatEigHImageType::Pointer MatEigHImagePointerType; |
|
|
41 |
typedef MatEigHImageType::RegionType MatRegionType; |
|
|
42 |
typedef MatEigHImageType::PointType MatPointType; |
|
|
43 |
typedef MatEigHImageType::SpacingType MatSpacingType; |
|
|
44 |
|
|
|
45 |
typedef VecEigHImageType::Pointer VecEigHImagePointerType; |
|
|
46 |
typedef itk::ImageRegionIteratorWithIndex<HFilterType::OutputImageType> HIterType; |
|
|
47 |
|
|
|
48 |
class cmp |
|
|
49 |
{ |
|
|
50 |
public: |
|
|
51 |
bool operator() ( HessianVoxelType a, HessianVoxelType b ) |
|
|
52 |
{ |
|
|
53 |
return std::abs(a) < std::abs(b) ; |
|
|
54 |
} |
|
|
55 |
}; |
|
|
56 |
|
|
|
57 |
class EigValHessian { |
|
|
58 |
public: |
|
|
59 |
MatRegionType region; |
|
|
60 |
MatSpacingType spacing; |
|
|
61 |
MatPointType origin; |
|
|
62 |
|
|
|
63 |
CastFilterType::Pointer CastFilter; |
|
|
64 |
HFilterType::Pointer HFilter; |
|
|
65 |
|
|
|
66 |
EigValAnalysisType EigValAnalysis; |
|
|
67 |
|
|
|
68 |
VecEigHImagePointerType VecEigHImagePointer; |
|
|
69 |
|
|
|
70 |
OutputImageType::Pointer OutputImage; |
|
|
71 |
|
|
|
72 |
ImportFilterType::Pointer importFilter; |
|
|
73 |
|
|
|
74 |
std::unordered_set<outVoxelType> label_set; |
|
|
75 |
|
|
|
76 |
MedianImageFilterType::Pointer medianFilter; |
|
|
77 |
|
|
|
78 |
EigValHessian(const InputImageType::Pointer& image, float sigma, float alpha, float beta, float gama) { |
|
|
79 |
// This method is to compute the Hessian matrix by ITK filter: HessianRecursiveGaussianImageFilter |
|
|
80 |
// Furthermore, calculte the fissure structure measurement with given parameters and then using vector |
|
|
81 |
// based region growing method to segment fissures. |
|
|
82 |
// :params image: the 3D lung mask image |
|
|
83 |
// :params sigma: the standard deviation for Gaussian function in Hessian matrix |
|
|
84 |
// :params alpha, beta, gama: parameters for fissure representation |
|
|
85 |
VecVoxType EigVal; |
|
|
86 |
MatVoxType EigMat,tmpMat; |
|
|
87 |
for(int i=0;i<3;i++) |
|
|
88 |
for(int j=0;j<3;j++) |
|
|
89 |
EigMat[i][j]=0; |
|
|
90 |
|
|
|
91 |
region=image->GetLargestPossibleRegion(); |
|
|
92 |
spacing=image->GetSpacing(); |
|
|
93 |
origin=image->GetOrigin(); |
|
|
94 |
|
|
|
95 |
// initialize the Hassian filter |
|
|
96 |
CastFilter = CastFilterType::New(); |
|
|
97 |
HFilter = HFilterType::New(); |
|
|
98 |
HFilter->SetSigma(sigma); |
|
|
99 |
|
|
|
100 |
EigValAnalysis.SetDimension(3); |
|
|
101 |
CastFilter->SetInput(image); |
|
|
102 |
HFilter->SetInput(CastFilter->GetOutput()); |
|
|
103 |
|
|
|
104 |
printf("Processing HFilter\n"); |
|
|
105 |
HFilter->Update(); |
|
|
106 |
|
|
|
107 |
VecEigHImagePointer=VecEigHImageType::New(); |
|
|
108 |
VecEigHImagePointer->SetRegions(region); |
|
|
109 |
VecEigHImagePointer->SetOrigin(origin); |
|
|
110 |
VecEigHImagePointer->SetSpacing(spacing); |
|
|
111 |
VecEigHImagePointer->Allocate(); |
|
|
112 |
|
|
|
113 |
EigVal[0]=EigVal[1]=EigVal[2]=0; |
|
|
114 |
VecEigHImagePointer->FillBuffer(EigMat[0]); |
|
|
115 |
|
|
|
116 |
OutputImage = OutputImageType::New(); |
|
|
117 |
OutputImage->SetRegions( region ); |
|
|
118 |
OutputImage->Allocate(true); // initialize buffer to zero |
|
|
119 |
|
|
|
120 |
HIterType HIter(HFilter->GetOutput(),region); |
|
|
121 |
|
|
|
122 |
OutputIterType OutputIter(VecEigHImagePointer,region); |
|
|
123 |
|
|
|
124 |
itk::SymmetricSecondRankTensor<float,3> Tensor; |
|
|
125 |
|
|
|
126 |
bool fissure_cond = true; |
|
|
127 |
|
|
|
128 |
InputImageIterType InputImageIter(image, region); |
|
|
129 |
|
|
|
130 |
// this is the mean and std value for vessel which is compute according to |
|
|
131 |
// histogram analysis in previous result. |
|
|
132 |
outVoxelType mean = 198.275350; |
|
|
133 |
outVoxelType std = 42.571917; |
|
|
134 |
|
|
|
135 |
outVoxelType vessel_thesh = mean - 3 * std; |
|
|
136 |
|
|
|
137 |
for(HIter.GoToBegin(),OutputIter.GoToBegin(),InputImageIter.GoToBegin(); |
|
|
138 |
!HIter.IsAtEnd()&&!OutputIter.IsAtEnd()&&!InputImageIter.IsAtEnd(); |
|
|
139 |
++HIter,++OutputIter,++InputImageIter){ |
|
|
140 |
Tensor=HIter.Get(); |
|
|
141 |
tmpMat[0][0]=Tensor[0]; |
|
|
142 |
tmpMat[0][1]=Tensor[1]; |
|
|
143 |
tmpMat[1][0]=Tensor[1]; |
|
|
144 |
tmpMat[0][2]=Tensor[2]; |
|
|
145 |
tmpMat[2][0]=Tensor[2]; |
|
|
146 |
tmpMat[1][1]=Tensor[3]; |
|
|
147 |
tmpMat[2][1]=Tensor[4]; |
|
|
148 |
tmpMat[1][2]=Tensor[4]; |
|
|
149 |
tmpMat[2][2]=Tensor[5]; |
|
|
150 |
|
|
|
151 |
// compute the eigenvalues given a 3*3 Hessian matrix. |
|
|
152 |
EigValAnalysis.ComputeEigenValuesAndVectors(tmpMat,EigVal,EigMat); |
|
|
153 |
|
|
|
154 |
// obtain the maximum absolute value for eigenvalues |
|
|
155 |
HessianVoxelType sortedEigVal[3] = {EigVal[0],EigVal[1],EigVal[2]}; |
|
|
156 |
|
|
|
157 |
std::sort(sortedEigVal, sortedEigVal+3, cmp()); |
|
|
158 |
|
|
|
159 |
// Compute Structure |
|
|
160 |
HessianVoxelType theta; |
|
|
161 |
if (sortedEigVal[2] >= 0){ |
|
|
162 |
theta = 0; |
|
|
163 |
}else{ |
|
|
164 |
theta = 1; |
|
|
165 |
} |
|
|
166 |
HessianVoxelType Fstructure, Fsheet, Sfissure; |
|
|
167 |
Fstructure = theta * exp(-1*(pow((std::abs(sortedEigVal[2])-alpha)/beta,6))); |
|
|
168 |
Fsheet = exp(-1*(pow(sortedEigVal[1]/gama,6))); |
|
|
169 |
|
|
|
170 |
Sfissure = Fstructure * Fsheet; |
|
|
171 |
|
|
|
172 |
// Convert to uint8 value |
|
|
173 |
VoxelType pixel_val = (InputImageIter.Get() + 1024) / 4; |
|
|
174 |
|
|
|
175 |
// Thresholding the result fissure structure measurement |
|
|
176 |
fissure_cond = Sfissure > 0.8 && pixel_val < vessel_thesh ? true : false; |
|
|
177 |
|
|
|
178 |
// Save the corresponding eigenvector for the maximum eigenvalue |
|
|
179 |
for (int i = 0; i < 3; i++){ |
|
|
180 |
if (EigVal[i] == sortedEigVal[2] && fissure_cond){ |
|
|
181 |
OutputIter.Set(EigMat[i]); |
|
|
182 |
break; |
|
|
183 |
} |
|
|
184 |
} |
|
|
185 |
|
|
|
186 |
} |
|
|
187 |
|
|
|
188 |
printf("Processing computing eigenvalues and eigenvectors\n"); |
|
|
189 |
VecEigHImagePointer->Update(); |
|
|
190 |
printf("Finish computing eigenvalues and eigenvectors\n"); |
|
|
191 |
|
|
|
192 |
// Compute the vector based region growing with given eigenvector. |
|
|
193 |
const OutputImageType::RegionType region = VecEigHImagePointer->GetBufferedRegion(); |
|
|
194 |
const OutputImageType::SizeType size = region.GetSize(); |
|
|
195 |
const unsigned int xs = size[0]; |
|
|
196 |
const unsigned int ys = size[1]; |
|
|
197 |
const unsigned int zs = size[2]; |
|
|
198 |
float label = 1; |
|
|
199 |
for (int z = 0; z < zs; z++){ |
|
|
200 |
for (int y = 0; y < ys; y++){ |
|
|
201 |
for (int x = 0; x < xs; x++){ |
|
|
202 |
PointType point; |
|
|
203 |
point[0] = x; |
|
|
204 |
point[1] = y; |
|
|
205 |
point[2] = z; |
|
|
206 |
OutputImageType::IndexType out_index; |
|
|
207 |
VecEigHImageType::IndexType vec_index; |
|
|
208 |
|
|
|
209 |
OutputImage->TransformPhysicalPointToIndex( point, out_index ); |
|
|
210 |
VecEigHImagePointer->TransformPhysicalPointToIndex( point, vec_index ); |
|
|
211 |
VecEigHImageType::PixelType p_vec = VecEigHImagePointer->GetPixel(vec_index); |
|
|
212 |
|
|
|
213 |
if (OutputImage->GetPixel(out_index) == 0 && p_vec[0]+p_vec[1]+p_vec[2] != 0){ |
|
|
214 |
int volume = 1; |
|
|
215 |
int *vol_point = &volume; |
|
|
216 |
this->region_growing(point, label, vol_point); |
|
|
217 |
label = label + 1; |
|
|
218 |
} |
|
|
219 |
} |
|
|
220 |
} |
|
|
221 |
} |
|
|
222 |
} |
|
|
223 |
void region_growing(PointType, float, int *); |
|
|
224 |
}; |
|
|
225 |
void EigValHessian::region_growing(PointType point, float label, int *vol_point){ |
|
|
226 |
// This function is to compute the vector based region growing. |
|
|
227 |
// :params point: the point for region growing |
|
|
228 |
// :params label: point label |
|
|
229 |
// :params vol_point: the volume for given label to limit the number of recursive. |
|
|
230 |
int x = point[0]; int y = point[1]; int z = point[2]; |
|
|
231 |
const OutputImageType::RegionType region = VecEigHImagePointer->GetBufferedRegion(); |
|
|
232 |
const OutputImageType::SizeType size = region.GetSize(); |
|
|
233 |
const unsigned int xs = size[0]; |
|
|
234 |
const unsigned int ys = size[1]; |
|
|
235 |
const unsigned int zs = size[2]; |
|
|
236 |
|
|
|
237 |
PointType neighbors[6]; |
|
|
238 |
neighbors[0][0] = x+1; neighbors[1][0] = x-1; neighbors[2][0] = x; neighbors[3][0] = x; neighbors[4][0] = x; neighbors[5][0] = x; |
|
|
239 |
neighbors[0][1] = y; neighbors[1][1] = y; neighbors[2][1] = y+1; neighbors[3][1] = y-1; neighbors[4][1] = y; neighbors[5][1] = y; |
|
|
240 |
neighbors[0][2] = z; neighbors[1][2] = z; neighbors[2][2] = z; neighbors[3][2] = z; neighbors[4][2] = z+1; neighbors[5][2] = z-1; |
|
|
241 |
|
|
|
242 |
VecEigHImageType::IndexType p_index; |
|
|
243 |
VecEigHImagePointer->TransformPhysicalPointToIndex( point, p_index ); |
|
|
244 |
VecEigHImageType::PixelType p = VecEigHImagePointer->GetPixel( p_index ); |
|
|
245 |
|
|
|
246 |
for (int i = 0; i < 6; i++){ |
|
|
247 |
if (neighbors[i][0] >= 0 && neighbors[i][0] < xs && |
|
|
248 |
neighbors[i][1] >= 0 && neighbors[i][1] < ys && |
|
|
249 |
neighbors[i][2] >= 0 && neighbors[i][2] < zs){ |
|
|
250 |
OutputImageType::IndexType out_index; |
|
|
251 |
OutputImage->TransformPhysicalPointToIndex( neighbors[i], out_index ); |
|
|
252 |
if (OutputImage->GetPixel(out_index) == 0){ |
|
|
253 |
VecEigHImageType::IndexType vec_index; |
|
|
254 |
VecEigHImagePointer->TransformPhysicalPointToIndex( neighbors[i], vec_index ); |
|
|
255 |
VecEigHImageType::PixelType np = VecEigHImagePointer->GetPixel( vec_index ); |
|
|
256 |
float product = np[0] * p[0] + np[1] * p[1] + np[2] * p[2]; |
|
|
257 |
if (product > 0.9){ |
|
|
258 |
*vol_point = *vol_point + 1; |
|
|
259 |
OutputImage->SetPixel( out_index, label); |
|
|
260 |
this->region_growing(neighbors[i], label, vol_point); |
|
|
261 |
} |
|
|
262 |
} |
|
|
263 |
} |
|
|
264 |
} |
|
|
265 |
} |
|
|
266 |
|
|
|
267 |
|
|
|
268 |
|
|
|
269 |
int main( int argc, char * argv[] ) |
|
|
270 |
{ |
|
|
271 |
time_t tStart = clock(); |
|
|
272 |
|
|
|
273 |
if( argc < 2 ) { |
|
|
274 |
std::cerr << "Usage: " << std::endl; |
|
|
275 |
std::cerr << argv[0] << " inputImageFile outputImageFile" << std::endl; |
|
|
276 |
return EXIT_FAILURE; |
|
|
277 |
} |
|
|
278 |
|
|
|
279 |
typedef itk::ImageFileReader< InputImageType > readerType; |
|
|
280 |
|
|
|
281 |
float sigma = 0.5; |
|
|
282 |
float alpha = 90; |
|
|
283 |
float beta = 120; |
|
|
284 |
float gama = 100; |
|
|
285 |
|
|
|
286 |
// Read Image |
|
|
287 |
readerType::Pointer reader = readerType::New(); |
|
|
288 |
reader->SetFileName( argv[1] ); |
|
|
289 |
reader->Update(); |
|
|
290 |
|
|
|
291 |
// Compute eigenvalues |
|
|
292 |
std::cout << " Compute Eigenvalues " << std::endl; |
|
|
293 |
EigValHessian eigenvalues = EigValHessian::EigValHessian( reader->GetOutput(), sigma, alpha, beta, gama ); |
|
|
294 |
|
|
|
295 |
std::cout << " Saving Image..." << std::endl; |
|
|
296 |
typedef itk::ImageFileWriter < OutputImageType > WriterType; |
|
|
297 |
WriterType::Pointer writer = WriterType::New(); |
|
|
298 |
writer->SetFileName( argv[2] ); |
|
|
299 |
writer->SetInput( eigenvalues.OutputImage ); |
|
|
300 |
|
|
|
301 |
writer->Update(); |
|
|
302 |
printf("Time taken: %.2fs\n", (float)(clock() - tStart)/CLOCKS_PER_SEC); |
|
|
303 |
|
|
|
304 |
return EXIT_SUCCESS; |
|
|
305 |
} |