1 /*=========================================================================
4 Module: $RCSfile: gdcmOrientation.cxx,v $
6 Date: $Date: 2005/09/20 15:11:19 $
7 Version: $Revision: 1.10 $
9 Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de
10 l'Image). All rights reserved. See Doc/License.txt or
11 http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details.
13 This software is distributed WITHOUT ANY WARRANTY; without even
14 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 PURPOSE. See the above copyright notices for more information.
17 =========================================================================*/
19 #include "gdcmOrientation.h"
21 #include "gdcmDebug.h"
22 #include <math.h> // for sqrt
26 //--------------------------------------------------------------------
27 // THERALYS Algorithm to determine the most similar basic orientation
29 // Transliterated from original Python code.
30 // Kept as close as possible to the original code
31 // in order to speed up any further modif of Python code :-(
32 //-----------------------------------------------------------------------
35 * \brief THERALYS' Algorithm to determine the most similar basic orientation
36 * (Axial, Coronal, Sagital) of the image
37 * \note Should be run on the first gdcm::File of a 'coherent' Serie
38 * @return orientation code
39 * # 0 : Not Applicable (neither 0020,0037 Image Orientation Patient
40 * # nor 0020,0032 Image Position found)
44 * # -2 : Coronal invert
46 * # -3 : Sagital invert
48 * # -4 : Heart Axial invert
50 * # -5 : Heart Coronal invert
52 * # -6 : Heart Sagital invert
54 double Orientation::TypeOrientation( File *f )
57 bool succ = f->GetImageOrientationPatient( iop );
60 gdcmErrorMacro( "No Image Orientation (0020,0037) found in the file, cannot proceed." )
64 std::cout << " iop : ";
66 std::cout << iop[i] << " ";
67 std::cout << std::endl;
72 ori1.x = iop[0]; ori1.y = iop[1]; ori1.z = iop[2];
73 ori2.x = iop[3]; ori2.y = iop[4]; ori2.z = iop[5];
75 // two perpendicular vectors describe one plane
76 double dicPlane[6][2][3] =
77 { { { 1, 0, 0 },{ 0, 1, 0 } }, // Axial
78 { { 1, 0, 0 },{ 0, 0, -1 } }, // Coronal
79 { { 0, 1, 0 },{ 0, 0, -1 } }, // Sagittal
80 { { 0.8, 0.5, 0.0 },{-0.1, 0.1 , -0.95 } }, // Axial - HEART
81 { { 0.8, 0.5, 0.0 },{-0.6674, 0.687, 0.1794} }, // Coronal - HEART
82 { {-0.1, 0.1, -0.95},{-0.6674, 0.687, 0.1794} } // Sagittal - HEART
88 Res res; // [ <result> , <memory of the last succes calcule> ]
92 std::cout << "-------------- res : " << res.first << "|" << res.second
95 for (int numDicPlane=0; numDicPlane<6; numDicPlane++)
99 refA.x = dicPlane[numDicPlane][0][0];
100 refA.y = dicPlane[numDicPlane][0][1];
101 refA.z = dicPlane[numDicPlane][0][2];
103 refB.x = dicPlane[numDicPlane][1][0];
104 refB.y = dicPlane[numDicPlane][1][1];
105 refB.z = dicPlane[numDicPlane][1][2];
106 res=VerfCriterion( i, CalculLikelyhood2Vec(refA,refB,ori1,ori2), res );
107 std::cout << "-------------- res : " << res.first << "|" << res.second
109 res=VerfCriterion( -i, CalculLikelyhood2Vec(refB,refA,ori1,ori2), res );
110 std::cout << "-------------- res : " << res.first << "|" << res.second
116 // res=[0,99999] ## [ <result> , <memory of the last succes calculus> ]
117 // for plane in dicPlane:
121 // res=self.VerfCriterion( i , self.CalculLikelyhood2Vec(refA,refB,ori1,ori2) , res )
122 // res=self.VerfCriterion( -i , self.CalculLikelyhood2Vec(refB,refA,ori1,ori2) , res )
128 Orientation::VerfCriterion(int typeCriterion, double criterionNew, Res const &in)
131 // double type = in.first;
132 double criterion = in.second;
133 if (/*criterionNew < 0.1 && */criterionNew < criterion)
135 res.first = typeCriterion;
136 res.second = criterionNew;
140 // criterion = res[1]
141 // # if criterionNew<0.1 and criterionNew<criterion:
142 // if criterionNew<criterion:
143 // criterion=criterionNew
144 // type=typeCriterion
145 // return [ type , criterion ]
150 inline double square_dist(vector3D const &v1, vector3D const &v2)
153 res = (v1.x - v2.x)*(v1.x - v2.x) +
154 (v1.y - v2.y)*(v1.y - v2.y) +
155 (v1.z - v2.z)*(v1.z - v2.z);
159 //------------------------- Purpose : -----------------------------------
160 //- This function determines the orientation similarity of two planes.
161 // Each plane is described by two vectors.
162 //------------------------- Parameters : --------------------------------
163 //- <refA> : - type : vector 3D (double)
164 //- <refB> : - type : vector 3D (double)
165 // - Description of the first plane
166 //- <ori1> : - type : vector 3D (double)
167 //- <ori2> : - type : vector 3D (double)
168 // - Description of the second plane
169 //------------------------- Return : ------------------------------------
170 // double : 0 if the planes are perpendicular. While the difference of
171 // the orientation between the planes are big more enlarge is
173 //------------------------- Other : -------------------------------------
174 // The calculus is based with vectors normalice
176 Orientation::CalculLikelyhood2Vec(vector3D const &refA, vector3D const &refB,
177 vector3D const &ori1, vector3D const &ori2 )
180 vector3D ori3 = ProductVectorial(ori1,ori2);
181 vector3D refC = ProductVectorial(refA,refB);
182 double res = square_dist(refC, ori3);
187 //------------------------- Purpose : -----------------------------------
188 //- Calculus of the poduct vectorial between two vectors 3D
189 //------------------------- Parameters : --------------------------------
190 //- <vec1> : - type : vector 3D (double)
191 //- <vec2> : - type : vector 3D (double)
192 //------------------------- Return : ------------------------------------
193 // (vec) : - Vector 3D
194 //------------------------- Other : -------------------------------------
196 Orientation::ProductVectorial(vector3D const &vec1, vector3D const &vec2)
199 vec3.x = vec1.y*vec2.z - vec1.z*vec2.y;
200 vec3.y = -( vec1.x*vec2.z - vec1.z*vec2.x);
201 vec3.z = vec1.x*vec2.y - vec1.y*vec2.x;
206 } // end namespace gdcm
211 // ---------------------------------------------------------------------------
212 // Here is the original Python code, kindly supplied by THERALYS
214 // C++ code doesn't give good results
219 def TypeOrientation(self,file0):
221 # ------------------------- Purpose : -----------------------------------
222 # - This function compare the orientation of the given image and the
223 # basics orientations (Axial, Cornal, Sagital)
224 # ------------------------- Parameters : --------------------------------
225 # - <file0> : - type : string
226 # - The name of the first image file of the serie
227 # ------------------------- Return : ------------------------------------
231 # -2 : Coronal invert
233 # -3 : Sagital invert
235 # -4 : Heart Axial invert
237 # -5 : Heart Coronal invert
239 # -6 : Heart Sagital invert
241 # ------------------------- Other : -------------------------------------
242 # This method finds the most similar basic orientation.
245 toRead = gdcm.File(file0)
246 ValDict = GetValuesDict(toRead)
248 imageOrientation=ValDict["Image Orientation (Patient)"]
250 imageOrientation=ValDict["Image Orientation"]
252 ori1=[float(split(imageOrientation,"\\")[0]),\
253 float(split(imageOrientation,"\\")[1]),\
254 float(split(imageOrientation,"\\")[2])]
255 ori2=[float(split(imageOrientation,"\\")[3]),\
256 float(split(imageOrientation,"\\")[4]),\
257 float(split(imageOrientation,"\\")[5])]
259 ## two vectors perpendicular describe one plane
260 dicPlane=[ [ [1,0,0],[0,1,0] ], ## Axial
261 [ [1,0,0],[0,0,-1] ], ## Coronal
262 [ [0,1,0],[0,0,-1] ], ## Sagittal
263 [ [ 0.8 , 0.5 , 0.0 ],[-0.1 , 0.1 , -0.95] ],## Axial - HEART
264 [ [ 0.8 , 0.5 , 0.0 ],[-0.6674 , 0.687 , 0.1794] ],## Coronal - HEART
265 [ [-0.1 , 0.1 , -0.95],[-0.6674 , 0.687 , 0.1794] ] ] ## Sagittal - HEART
268 res=[0,99999] ## [ <result> , <memory of the last succes calcule> ]
269 for plane in dicPlane:
273 res=self.VerfCriterion( i , self.CalculLikelyhood2Vec(refA,refB,ori1,ori2) , res )
274 res=self.VerfCriterion( -i , self.CalculLikelyhood2Vec(refB,refA,ori1,ori2) , res )
281 def VerfCriterion(self,typeCriterion,criterionNew,res):
284 # if criterionNew<0.1 and criterionNew<criterion:
285 if criterionNew<criterion:
286 criterion=criterionNew
288 return [ type , criterion ]
291 def CalculLikelyhood2Vec(self,refA,refB,ori1,ori2):
293 # ------------------------- Purpose : -----------------------------------
294 # - This function determine the orientation similarity of two planes.
295 # Each plane is described by two vector.
296 # ------------------------- Parameters : --------------------------------
297 # - <refA> : - type : vector 3D (float)
298 # - <refB> : - type : vector 3D (float)
299 # - Description of the first plane
300 # - <ori1> : - type : vector 3D (float)
301 # - <ori2> : - type : vector 3D (float)
302 # - Description of the second plane
303 # ------------------------- Return : ------------------------------------
304 # float : 0 if the planes are perpendicular.
305 # While the difference of the orientation between the planes
306 # are big more enlarge is
308 # ------------------------- Other : -------------------------------------
309 # The calculus is based with vectors normalice
312 ori3=self.ProductVectorial(ori1,ori2)
313 refC=self.ProductVectorial(refA,refB)
314 res=math.pow(refC[0]-ori3[0],2) + math.pow(refC[1]-ori3[1],2) + math.pow(refC[2]-ori3[2],2)
315 return math.sqrt(res)
317 def ProductVectorial(self,vec1,vec2):
319 # ------------------------- Purpose : -----------------------------------
320 # - Calculus of the poduct vectorial between two vectors 3D
321 # ------------------------- Parameters : --------------------------------
322 # - <vec1> : - type : vector 3D (float)
323 # - <vec2> : - type : vector 3D (float)
324 # ------------------------- Return : ------------------------------------
325 # (vec) : - Vector 3D
326 # ------------------------- Other : -------------------------------------
329 vec3[0]=vec1[1]*vec2[2] - vec1[2]*vec2[1]
330 vec3[1]=-( vec1[0]*vec2[2] - vec1[2]*vec2[0])
331 vec3[2]=vec1[0]*vec2[1] - vec1[1]*vec2[0]
334 def GetValuesDict(image):
336 Returns a dictionnary containing values associated with Field Names
337 dict["Dicom Field Name"]="Dicom field value"
339 val=image.GetFirstEntry()
342 if isinstance(val,gdcm.ValEntryPtr):
343 dic[val.GetName()]=val.GetValue()
344 val=image.GetNextEntry()