From 99a32e6b6a4b4361b0003685da13e03cdf479cf0 Mon Sep 17 00:00:00 2001 From: heagenb03 Date: Thu, 22 Jan 2026 15:40:34 -0600 Subject: [PATCH 1/2] Add intial project files --- matlab/atlas-label-info.csv | 264 +++---- matlab/braincolor_hierarchy_STAPLE.txt | 266 +++---- matlab/load_nii.m | 276 +++---- matlab/load_nii_ext.m | 296 ++++---- matlab/load_nii_hdr.m | 560 +++++++------- matlab/load_nii_img.m | 784 ++++++++++---------- matlab/load_untouch0_nii_hdr.m | 400 +++++----- matlab/load_untouch_nii.m | 256 +++---- matlab/load_untouch_nii_hdr.m | 434 +++++------ matlab/load_untouch_nii_img.m | 970 ++++++++++++------------- matlab/save_nii.m | 502 ++++++------- matlab/save_nii_ext.m | 76 +- matlab/save_nii_hdr.m | 454 ++++++------ matlab/save_untouch0_nii_hdr.m | 438 +++++------ matlab/save_untouch_nii.m | 394 +++++----- matlab/save_untouch_nii_hdr.m | 414 +++++------ matlab/torchsrc/models/Unet.py | 660 ++++++++--------- matlab/torchsrc/models/Unet_online.py | 186 ++--- matlab/torchsrc/models/fcn32s_BN.py | 546 +++++++------- 19 files changed, 4088 insertions(+), 4088 deletions(-) diff --git a/matlab/atlas-label-info.csv b/matlab/atlas-label-info.csv index a67d80c..9bfc314 100644 --- a/matlab/atlas-label-info.csv +++ b/matlab/atlas-label-info.csv @@ -1,132 +1,132 @@ -4,3rd Ventricle -11,4th Ventricle -23,Right Accumbens Area -30,Left Accumbens Area -31,Right Amygdala -32,Left Amygdala -35,Brain Stem -36,Right Caudate -37,Left Caudate -38,Right Cerebellum Exterior -39,Left Cerebellum Exterior -40,Right Cerebellum White Matter -41,Left Cerebellum White Matter -44,Right Cerebral White Matter -45,Left Cerebral White Matter -47,Right Hippocampus -48,Left Hippocampus -49,Right Inf Lat Vent -50,Left Inf Lat Vent -51,Right Lateral Ventricle -52,Left Lateral Ventricle -55,Right Pallidum -56,Left Pallidum -57,Right Putamen -58,Left Putamen -59,Right Thalamus Proper -60,Left Thalamus Proper -61,Right Ventral DC -62,Left Ventral DC -71,Cerebellar Vermal Lobules I-V -72,Cerebellar Vermal Lobules VI-VII -73,Cerebellar Vermal Lobules VIII-X -75,Left Basal Forebrain -76,Right Basal Forebrain -100,Right ACgG anterior cingulate gyrus -101,Left ACgG anterior cingulate gyrus -102,Right AIns anterior insula -103,Left AIns anterior insula -104,Right AOrG anterior orbital gyrus -105,Left AOrG anterior orbital gyrus -106,Right AnG angular gyrus -107,Left AnG angular gyrus -108,Right Calc calcarine cortex -109,Left Calc calcarine cortex -112,Right CO central operculum -113,Left CO central operculum -114,Right Cun cuneus -115,Left Cun cuneus -116,Right Ent entorhinal area -117,Left Ent entorhinal area -118,Right FO frontal operculum -119,Left FO frontal operculum -120,Right FRP frontal pole -121,Left FRP frontal pole -122,Right FuG fusiform gyrus -123,Left FuG fusiform gyrus -124,Right GRe gyrus rectus -125,Left GRe gyrus rectus -128,Right IOG inferior occipital gyrus -129,Left IOG inferior occipital gyrus -132,Right ITG inferior temporal gyrus -133,Left ITG inferior temporal gyrus -134,Right LiG lingual gyrus -135,Left LiG lingual gyrus -136,Right LOrG lateral orbital gyrus -137,Left LOrG lateral orbital gyrus -138,Right MCgG middle cingulate gyrus -139,Left MCgG middle cingulate gyrus -140,Right MFC medial frontal cortex -141,Left MFC medial frontal cortex -142,Right MFG middle frontal gyrus -143,Left MFG middle frontal gyrus -144,Right MOG middle occipital gyrus -145,Left MOG middle occipital gyrus -146,Right MOrG medial orbital gyrus -147,Left MOrG medial orbital gyrus -148,Right MPoG postcentral gyrus medial segment -149,Left MPoG postcentral gyrus medial segment -150,Right MPrG precentral gyrus medial segment -151,Left MPrG precentral gyrus medial segment -152,Right MSFG superior frontal gyrus medial segment -153,Left MSFG superior frontal gyrus medial segment -154,Right MTG middle temporal gyrus -155,Left MTG middle temporal gyrus -156,Right OCP occipital pole -157,Left OCP occipital pole -160,Right OFuG occipital fusiform gyrus -161,Left OFuG occipital fusiform gyrus -162,Right OpIFG opercular part of the inferior frontal gyrus -163,Left OpIFG opercular part of the inferior frontal gyrus -164,Right OrIFG orbital part of the inferior frontal gyrus -165,Left OrIFG orbital part of the inferior frontal gyrus -166,Right PCgG posterior cingulate gyrus -167,Left PCgG posterior cingulate gyrus -168,Right PCu precuneus -169,Left PCu precuneus -170,Right PHG parahippocampal gyrus -171,Left PHG parahippocampal gyrus -172,Right PIns posterior insula -173,Left PIns posterior insula -174,Right PO parietal operculum -175,Left PO parietal operculum -176,Right PoG postcentral gyrus -177,Left PoG postcentral gyrus -178,Right POrG posterior orbital gyrus -179,Left POrG posterior orbital gyrus -180,Right PP planum polare -181,Left PP planum polare -182,Right PrG precentral gyrus -183,Left PrG precentral gyrus -184,Right PT planum temporale -185,Left PT planum temporale -186,Right SCA subcallosal area -187,Left SCA subcallosal area -190,Right SFG superior frontal gyrus -191,Left SFG superior frontal gyrus -192,Right SMC supplementary motor cortex -193,Left SMC supplementary motor cortex -194,Right SMG supramarginal gyrus -195,Left SMG supramarginal gyrus -196,Right SOG superior occipital gyrus -197,Left SOG superior occipital gyrus -198,Right SPL superior parietal lobule -199,Left SPL superior parietal lobule -200,Right STG superior temporal gyrus -201,Left STG superior temporal gyrus -202,Right TMP temporal pole -203,Left TMP temporal pole -204,Right TrIFG triangular part of the inferior frontal gyrus -205,Left TrIFG triangular part of the inferior frontal gyrus -206,Right TTG transverse temporal gyrus -207,Left TTG transverse temporal gyrus +4,3rd Ventricle +11,4th Ventricle +23,Right Accumbens Area +30,Left Accumbens Area +31,Right Amygdala +32,Left Amygdala +35,Brain Stem +36,Right Caudate +37,Left Caudate +38,Right Cerebellum Exterior +39,Left Cerebellum Exterior +40,Right Cerebellum White Matter +41,Left Cerebellum White Matter +44,Right Cerebral White Matter +45,Left Cerebral White Matter +47,Right Hippocampus +48,Left Hippocampus +49,Right Inf Lat Vent +50,Left Inf Lat Vent +51,Right Lateral Ventricle +52,Left Lateral Ventricle +55,Right Pallidum +56,Left Pallidum +57,Right Putamen +58,Left Putamen +59,Right Thalamus Proper +60,Left Thalamus Proper +61,Right Ventral DC +62,Left Ventral DC +71,Cerebellar Vermal Lobules I-V +72,Cerebellar Vermal Lobules VI-VII +73,Cerebellar Vermal Lobules VIII-X +75,Left Basal Forebrain +76,Right Basal Forebrain +100,Right ACgG anterior cingulate gyrus +101,Left ACgG anterior cingulate gyrus +102,Right AIns anterior insula +103,Left AIns anterior insula +104,Right AOrG anterior orbital gyrus +105,Left AOrG anterior orbital gyrus +106,Right AnG angular gyrus +107,Left AnG angular gyrus +108,Right Calc calcarine cortex +109,Left Calc calcarine cortex +112,Right CO central operculum +113,Left CO central operculum +114,Right Cun cuneus +115,Left Cun cuneus +116,Right Ent entorhinal area +117,Left Ent entorhinal area +118,Right FO frontal operculum +119,Left FO frontal operculum +120,Right FRP frontal pole +121,Left FRP frontal pole +122,Right FuG fusiform gyrus +123,Left FuG fusiform gyrus +124,Right GRe gyrus rectus +125,Left GRe gyrus rectus +128,Right IOG inferior occipital gyrus +129,Left IOG inferior occipital gyrus +132,Right ITG inferior temporal gyrus +133,Left ITG inferior temporal gyrus +134,Right LiG lingual gyrus +135,Left LiG lingual gyrus +136,Right LOrG lateral orbital gyrus +137,Left LOrG lateral orbital gyrus +138,Right MCgG middle cingulate gyrus +139,Left MCgG middle cingulate gyrus +140,Right MFC medial frontal cortex +141,Left MFC medial frontal cortex +142,Right MFG middle frontal gyrus +143,Left MFG middle frontal gyrus +144,Right MOG middle occipital gyrus +145,Left MOG middle occipital gyrus +146,Right MOrG medial orbital gyrus +147,Left MOrG medial orbital gyrus +148,Right MPoG postcentral gyrus medial segment +149,Left MPoG postcentral gyrus medial segment +150,Right MPrG precentral gyrus medial segment +151,Left MPrG precentral gyrus medial segment +152,Right MSFG superior frontal gyrus medial segment +153,Left MSFG superior frontal gyrus medial segment +154,Right MTG middle temporal gyrus +155,Left MTG middle temporal gyrus +156,Right OCP occipital pole +157,Left OCP occipital pole +160,Right OFuG occipital fusiform gyrus +161,Left OFuG occipital fusiform gyrus +162,Right OpIFG opercular part of the inferior frontal gyrus +163,Left OpIFG opercular part of the inferior frontal gyrus +164,Right OrIFG orbital part of the inferior frontal gyrus +165,Left OrIFG orbital part of the inferior frontal gyrus +166,Right PCgG posterior cingulate gyrus +167,Left PCgG posterior cingulate gyrus +168,Right PCu precuneus +169,Left PCu precuneus +170,Right PHG parahippocampal gyrus +171,Left PHG parahippocampal gyrus +172,Right PIns posterior insula +173,Left PIns posterior insula +174,Right PO parietal operculum +175,Left PO parietal operculum +176,Right PoG postcentral gyrus +177,Left PoG postcentral gyrus +178,Right POrG posterior orbital gyrus +179,Left POrG posterior orbital gyrus +180,Right PP planum polare +181,Left PP planum polare +182,Right PrG precentral gyrus +183,Left PrG precentral gyrus +184,Right PT planum temporale +185,Left PT planum temporale +186,Right SCA subcallosal area +187,Left SCA subcallosal area +190,Right SFG superior frontal gyrus +191,Left SFG superior frontal gyrus +192,Right SMC supplementary motor cortex +193,Left SMC supplementary motor cortex +194,Right SMG supramarginal gyrus +195,Left SMG supramarginal gyrus +196,Right SOG superior occipital gyrus +197,Left SOG superior occipital gyrus +198,Right SPL superior parietal lobule +199,Left SPL superior parietal lobule +200,Right STG superior temporal gyrus +201,Left STG superior temporal gyrus +202,Right TMP temporal pole +203,Left TMP temporal pole +204,Right TrIFG triangular part of the inferior frontal gyrus +205,Left TrIFG triangular part of the inferior frontal gyrus +206,Right TTG transverse temporal gyrus +207,Left TTG transverse temporal gyrus diff --git a/matlab/braincolor_hierarchy_STAPLE.txt b/matlab/braincolor_hierarchy_STAPLE.txt index c8e368f..1c0b28e 100644 --- a/matlab/braincolor_hierarchy_STAPLE.txt +++ b/matlab/braincolor_hierarchy_STAPLE.txt @@ -1,134 +1,134 @@ -133,2,3,8,14,23,33,47,63,91,117,129,133 -0,0,0,0,0,0,0,0,0,0,0,0,0 -4,1,1,1,1,1,1,1,1,1,1,1,1 -11,1,2,2,2,2,2,2,2,2,2,2,2 -23,1,1,3,3,3,3,3,3,3,3,3,3 -30,1,1,3,4,4,4,4,4,4,4,4,4 -31,1,1,4,5,5,5,5,5,5,5,5,5 -32,1,1,4,6,6,6,6,6,6,6,6,6 -35,1,2,5,7,7,7,7,7,7,7,7,7 -36,1,1,3,3,3,3,8,8,8,8,8,8 -37,1,1,3,4,4,4,9,9,9,9,9,9 -38,1,2,6,8,8,8,10,10,10,10,10,10 -39,1,2,6,9,9,9,11,11,11,11,11,11 -40,1,2,6,8,10,10,12,12,12,12,12,12 -41,1,2,6,9,11,11,13,13,13,13,13,13 -44,1,1,7,10,12,12,14,14,14,14,14,14 -45,1,1,7,11,13,13,15,15,15,15,15,15 -47,1,1,4,5,5,5,5,5,5,16,16,16 -48,1,1,4,6,6,6,6,6,6,17,17,17 -49,1,1,1,12,14,14,16,16,16,18,18,18 -50,1,1,1,12,15,15,17,17,17,19,19,19 -51,1,1,1,12,14,16,18,18,18,20,20,20 -52,1,1,1,12,15,17,19,19,19,21,21,21 -55,1,1,3,3,3,18,20,20,20,22,22,22 -56,1,1,3,4,4,19,21,21,21,23,23,23 -57,1,1,3,3,3,18,22,22,22,24,24,24 -58,1,1,3,4,4,19,23,23,23,25,25,25 -59,1,1,3,3,16,20,24,24,24,26,26,26 -60,1,1,3,4,17,21,25,25,25,27,27,27 -61,1,1,3,3,16,22,26,26,26,28,28,28 -62,1,1,3,4,17,23,27,27,27,29,29,29 -71,1,2,6,13,18,24,28,28,28,30,30,30 -72,1,2,6,13,19,25,29,29,29,31,31,31 -73,1,2,6,13,20,26,30,30,30,32,32,32 -75,1,1,3,4,17,23,31,31,31,33,33,33 -76,1,1,3,3,16,22,32,32,32,34,34,34 -100,1,1,4,5,5,5,5,5,33,35,35,35 -101,1,1,4,6,6,6,6,6,34,36,36,36 -102,1,1,4,5,21,27,33,33,35,37,37,37 -103,1,1,4,6,22,28,34,34,36,38,38,38 -104,1,1,4,5,5,29,35,35,37,39,39,39 -105,1,1,4,6,6,30,36,36,38,40,40,40 -106,1,1,4,5,5,5,37,37,39,41,41,41 -107,1,1,4,6,6,6,38,38,40,42,42,42 -108,1,1,4,5,21,31,39,39,41,43,43,43 -109,1,1,4,6,22,32,40,40,42,44,44,44 -112,1,1,4,5,21,27,41,41,43,45,45,45 -113,1,1,4,6,22,28,42,42,44,46,46,46 -114,1,1,4,5,21,31,39,43,45,47,47,47 -115,1,1,4,6,22,32,40,44,46,48,48,48 -116,1,1,4,5,21,27,41,45,47,49,49,49 -117,1,1,4,6,22,28,42,46,48,50,50,50 -118,1,1,4,5,5,29,35,47,49,51,51,51 -119,1,1,4,6,6,30,36,48,50,52,52,52 -120,1,1,4,5,5,29,43,49,51,53,53,53 -121,1,1,4,6,6,30,44,50,52,54,54,54 -122,1,1,4,5,21,27,41,45,47,55,55,55 -123,1,1,4,6,22,28,42,46,48,56,56,56 -124,1,1,4,5,5,29,43,49,53,57,57,57 -125,1,1,4,6,6,30,44,50,54,58,58,58 -128,1,1,4,5,21,31,45,51,55,59,59,59 -129,1,1,4,6,22,32,46,52,56,60,60,60 -132,1,1,4,5,21,27,41,45,47,49,61,61 -133,1,1,4,6,22,28,42,46,48,50,62,62 -134,1,1,4,5,21,31,39,43,57,61,63,63 -135,1,1,4,6,22,32,40,44,58,62,64,64 -136,1,1,4,5,5,29,35,35,37,63,65,65 -137,1,1,4,6,6,30,36,36,38,64,66,66 -138,1,1,4,5,5,5,5,53,59,65,67,67 -139,1,1,4,6,6,6,6,54,60,66,68,68 -140,1,1,4,5,5,29,43,49,53,57,69,69 -141,1,1,4,6,6,30,44,50,54,58,70,70 -142,1,1,4,5,5,29,43,55,61,67,71,71 -143,1,1,4,6,6,30,44,56,62,68,72,72 -144,1,1,4,5,21,31,45,57,63,69,73,73 -145,1,1,4,6,22,32,46,58,64,70,74,74 -146,1,1,4,5,5,29,35,35,65,71,75,75 -147,1,1,4,6,6,30,36,36,66,72,76,76 -148,1,1,4,5,5,5,37,59,67,73,77,77 -149,1,1,4,6,6,6,38,60,68,74,78,78 -150,1,1,4,5,5,29,43,55,69,75,79,79 -151,1,1,4,6,6,30,44,56,70,76,80,80 -152,1,1,4,5,5,29,43,49,53,77,81,81 -153,1,1,4,6,6,30,44,50,54,78,82,82 -154,1,1,4,5,21,27,41,41,71,79,83,83 -155,1,1,4,6,22,28,42,42,72,80,84,84 -156,1,1,4,5,21,31,39,39,73,81,85,85 -157,1,1,4,6,22,32,40,40,74,82,86,86 -160,1,1,4,5,21,31,45,51,75,83,87,87 -161,1,1,4,6,22,32,46,52,76,84,88,88 -162,1,1,4,5,5,29,35,47,49,51,89,89 -163,1,1,4,6,6,30,36,48,50,52,90,90 -164,1,1,4,5,5,29,35,47,77,85,91,91 -165,1,1,4,6,6,30,36,48,78,86,92,92 -166,1,1,4,5,5,5,5,53,79,87,93,93 -167,1,1,4,6,6,6,6,54,80,88,94,94 -168,1,1,4,5,5,5,37,59,81,89,95,95 -169,1,1,4,6,6,6,38,60,82,90,96,96 -170,1,1,4,5,21,27,41,45,47,55,97,97 -171,1,1,4,6,22,28,42,46,48,56,98,98 -172,1,1,4,5,21,27,33,61,83,91,99,99 -173,1,1,4,6,22,28,34,62,84,92,100,100 -174,1,1,4,5,5,5,37,37,85,93,101,101 -175,1,1,4,6,6,6,38,38,86,94,102,102 -176,1,1,4,5,5,5,37,37,85,95,103,103 -177,1,1,4,6,6,6,38,38,86,96,104,104 -178,1,1,4,5,5,29,35,35,65,97,105,105 -179,1,1,4,6,6,30,36,36,66,98,106,106 -180,1,1,4,5,21,27,41,41,43,45,107,107 -181,1,1,4,6,22,28,42,42,44,46,108,108 -182,1,1,4,5,5,29,43,55,69,99,109,109 -183,1,1,4,6,6,30,44,56,70,100,110,110 -184,1,1,4,5,21,27,41,41,43,45,45,111 -185,1,1,4,6,22,28,42,42,44,46,46,112 -186,1,1,4,5,5,5,5,5,33,101,111,113 -187,1,1,4,6,6,6,6,6,34,102,112,114 -190,1,1,4,5,5,29,43,49,51,103,113,115 -191,1,1,4,6,6,30,44,50,52,104,114,116 -192,1,1,4,5,5,29,43,49,53,77,115,117 -193,1,1,4,6,6,30,44,50,54,78,116,118 -194,1,1,4,5,5,5,37,37,39,105,117,119 -195,1,1,4,6,6,6,38,38,40,106,118,120 -196,1,1,4,5,21,31,45,57,87,107,119,121 -197,1,1,4,6,22,32,46,58,88,108,120,122 -198,1,1,4,5,5,5,37,59,67,109,121,123 -199,1,1,4,6,6,6,38,60,68,110,122,124 -200,1,1,4,5,21,27,41,41,43,111,123,125 -201,1,1,4,6,22,28,42,42,44,112,124,126 -202,1,1,4,5,21,27,41,45,89,113,125,127 -203,1,1,4,6,22,28,42,46,90,114,126,128 -204,1,1,4,5,5,29,35,47,49,115,127,129 -205,1,1,4,6,6,30,36,48,50,116,128,130 -206,1,1,4,5,21,27,41,41,43,45,107,131 +133,2,3,8,14,23,33,47,63,91,117,129,133 +0,0,0,0,0,0,0,0,0,0,0,0,0 +4,1,1,1,1,1,1,1,1,1,1,1,1 +11,1,2,2,2,2,2,2,2,2,2,2,2 +23,1,1,3,3,3,3,3,3,3,3,3,3 +30,1,1,3,4,4,4,4,4,4,4,4,4 +31,1,1,4,5,5,5,5,5,5,5,5,5 +32,1,1,4,6,6,6,6,6,6,6,6,6 +35,1,2,5,7,7,7,7,7,7,7,7,7 +36,1,1,3,3,3,3,8,8,8,8,8,8 +37,1,1,3,4,4,4,9,9,9,9,9,9 +38,1,2,6,8,8,8,10,10,10,10,10,10 +39,1,2,6,9,9,9,11,11,11,11,11,11 +40,1,2,6,8,10,10,12,12,12,12,12,12 +41,1,2,6,9,11,11,13,13,13,13,13,13 +44,1,1,7,10,12,12,14,14,14,14,14,14 +45,1,1,7,11,13,13,15,15,15,15,15,15 +47,1,1,4,5,5,5,5,5,5,16,16,16 +48,1,1,4,6,6,6,6,6,6,17,17,17 +49,1,1,1,12,14,14,16,16,16,18,18,18 +50,1,1,1,12,15,15,17,17,17,19,19,19 +51,1,1,1,12,14,16,18,18,18,20,20,20 +52,1,1,1,12,15,17,19,19,19,21,21,21 +55,1,1,3,3,3,18,20,20,20,22,22,22 +56,1,1,3,4,4,19,21,21,21,23,23,23 +57,1,1,3,3,3,18,22,22,22,24,24,24 +58,1,1,3,4,4,19,23,23,23,25,25,25 +59,1,1,3,3,16,20,24,24,24,26,26,26 +60,1,1,3,4,17,21,25,25,25,27,27,27 +61,1,1,3,3,16,22,26,26,26,28,28,28 +62,1,1,3,4,17,23,27,27,27,29,29,29 +71,1,2,6,13,18,24,28,28,28,30,30,30 +72,1,2,6,13,19,25,29,29,29,31,31,31 +73,1,2,6,13,20,26,30,30,30,32,32,32 +75,1,1,3,4,17,23,31,31,31,33,33,33 +76,1,1,3,3,16,22,32,32,32,34,34,34 +100,1,1,4,5,5,5,5,5,33,35,35,35 +101,1,1,4,6,6,6,6,6,34,36,36,36 +102,1,1,4,5,21,27,33,33,35,37,37,37 +103,1,1,4,6,22,28,34,34,36,38,38,38 +104,1,1,4,5,5,29,35,35,37,39,39,39 +105,1,1,4,6,6,30,36,36,38,40,40,40 +106,1,1,4,5,5,5,37,37,39,41,41,41 +107,1,1,4,6,6,6,38,38,40,42,42,42 +108,1,1,4,5,21,31,39,39,41,43,43,43 +109,1,1,4,6,22,32,40,40,42,44,44,44 +112,1,1,4,5,21,27,41,41,43,45,45,45 +113,1,1,4,6,22,28,42,42,44,46,46,46 +114,1,1,4,5,21,31,39,43,45,47,47,47 +115,1,1,4,6,22,32,40,44,46,48,48,48 +116,1,1,4,5,21,27,41,45,47,49,49,49 +117,1,1,4,6,22,28,42,46,48,50,50,50 +118,1,1,4,5,5,29,35,47,49,51,51,51 +119,1,1,4,6,6,30,36,48,50,52,52,52 +120,1,1,4,5,5,29,43,49,51,53,53,53 +121,1,1,4,6,6,30,44,50,52,54,54,54 +122,1,1,4,5,21,27,41,45,47,55,55,55 +123,1,1,4,6,22,28,42,46,48,56,56,56 +124,1,1,4,5,5,29,43,49,53,57,57,57 +125,1,1,4,6,6,30,44,50,54,58,58,58 +128,1,1,4,5,21,31,45,51,55,59,59,59 +129,1,1,4,6,22,32,46,52,56,60,60,60 +132,1,1,4,5,21,27,41,45,47,49,61,61 +133,1,1,4,6,22,28,42,46,48,50,62,62 +134,1,1,4,5,21,31,39,43,57,61,63,63 +135,1,1,4,6,22,32,40,44,58,62,64,64 +136,1,1,4,5,5,29,35,35,37,63,65,65 +137,1,1,4,6,6,30,36,36,38,64,66,66 +138,1,1,4,5,5,5,5,53,59,65,67,67 +139,1,1,4,6,6,6,6,54,60,66,68,68 +140,1,1,4,5,5,29,43,49,53,57,69,69 +141,1,1,4,6,6,30,44,50,54,58,70,70 +142,1,1,4,5,5,29,43,55,61,67,71,71 +143,1,1,4,6,6,30,44,56,62,68,72,72 +144,1,1,4,5,21,31,45,57,63,69,73,73 +145,1,1,4,6,22,32,46,58,64,70,74,74 +146,1,1,4,5,5,29,35,35,65,71,75,75 +147,1,1,4,6,6,30,36,36,66,72,76,76 +148,1,1,4,5,5,5,37,59,67,73,77,77 +149,1,1,4,6,6,6,38,60,68,74,78,78 +150,1,1,4,5,5,29,43,55,69,75,79,79 +151,1,1,4,6,6,30,44,56,70,76,80,80 +152,1,1,4,5,5,29,43,49,53,77,81,81 +153,1,1,4,6,6,30,44,50,54,78,82,82 +154,1,1,4,5,21,27,41,41,71,79,83,83 +155,1,1,4,6,22,28,42,42,72,80,84,84 +156,1,1,4,5,21,31,39,39,73,81,85,85 +157,1,1,4,6,22,32,40,40,74,82,86,86 +160,1,1,4,5,21,31,45,51,75,83,87,87 +161,1,1,4,6,22,32,46,52,76,84,88,88 +162,1,1,4,5,5,29,35,47,49,51,89,89 +163,1,1,4,6,6,30,36,48,50,52,90,90 +164,1,1,4,5,5,29,35,47,77,85,91,91 +165,1,1,4,6,6,30,36,48,78,86,92,92 +166,1,1,4,5,5,5,5,53,79,87,93,93 +167,1,1,4,6,6,6,6,54,80,88,94,94 +168,1,1,4,5,5,5,37,59,81,89,95,95 +169,1,1,4,6,6,6,38,60,82,90,96,96 +170,1,1,4,5,21,27,41,45,47,55,97,97 +171,1,1,4,6,22,28,42,46,48,56,98,98 +172,1,1,4,5,21,27,33,61,83,91,99,99 +173,1,1,4,6,22,28,34,62,84,92,100,100 +174,1,1,4,5,5,5,37,37,85,93,101,101 +175,1,1,4,6,6,6,38,38,86,94,102,102 +176,1,1,4,5,5,5,37,37,85,95,103,103 +177,1,1,4,6,6,6,38,38,86,96,104,104 +178,1,1,4,5,5,29,35,35,65,97,105,105 +179,1,1,4,6,6,30,36,36,66,98,106,106 +180,1,1,4,5,21,27,41,41,43,45,107,107 +181,1,1,4,6,22,28,42,42,44,46,108,108 +182,1,1,4,5,5,29,43,55,69,99,109,109 +183,1,1,4,6,6,30,44,56,70,100,110,110 +184,1,1,4,5,21,27,41,41,43,45,45,111 +185,1,1,4,6,22,28,42,42,44,46,46,112 +186,1,1,4,5,5,5,5,5,33,101,111,113 +187,1,1,4,6,6,6,6,6,34,102,112,114 +190,1,1,4,5,5,29,43,49,51,103,113,115 +191,1,1,4,6,6,30,44,50,52,104,114,116 +192,1,1,4,5,5,29,43,49,53,77,115,117 +193,1,1,4,6,6,30,44,50,54,78,116,118 +194,1,1,4,5,5,5,37,37,39,105,117,119 +195,1,1,4,6,6,6,38,38,40,106,118,120 +196,1,1,4,5,21,31,45,57,87,107,119,121 +197,1,1,4,6,22,32,46,58,88,108,120,122 +198,1,1,4,5,5,5,37,59,67,109,121,123 +199,1,1,4,6,6,6,38,60,68,110,122,124 +200,1,1,4,5,21,27,41,41,43,111,123,125 +201,1,1,4,6,22,28,42,42,44,112,124,126 +202,1,1,4,5,21,27,41,45,89,113,125,127 +203,1,1,4,6,22,28,42,46,90,114,126,128 +204,1,1,4,5,5,29,35,47,49,115,127,129 +205,1,1,4,6,6,30,36,48,50,116,128,130 +206,1,1,4,5,21,27,41,41,43,45,107,131 207,1,1,4,6,22,28,42,42,44,46,108,132 \ No newline at end of file diff --git a/matlab/load_nii.m b/matlab/load_nii.m index 42415a5..841bd04 100644 --- a/matlab/load_nii.m +++ b/matlab/load_nii.m @@ -1,138 +1,138 @@ -% Load NIFTI or ANALYZE dataset. Support both *.nii and *.hdr/*.img -% file extension. If file extension is not provided, *.hdr/*.img will -% be used as default. -% -% A subset of NIFTI transform is included. For non-orthogonal rotation, -% shearing etc., please use 'reslice_nii.m' to reslice the NIFTI file. -% It will not cause negative effect, as long as you remember not to do -% slice time correction after reslicing the NIFTI file. Output variable -% nii will be in RAS orientation, i.e. X axis from Left to Right, -% Y axis from Posterior to Anterior, and Z axis from Inferior to -% Superior. -% -% Usage: nii = load_nii(filename, [img_idx], [dim5_idx], [dim6_idx], ... -% [dim7_idx], [old_RGB], [tolerance], [preferredForm]) -% -% filename - NIFTI or ANALYZE file name. -% -% img_idx (optional) - a numerical array of 4th dimension indices, -% which is the indices of image scan volume. The number of images -% scan volumes can be obtained from get_nii_frame.m, or simply -% hdr.dime.dim(5). Only the specified volumes will be loaded. -% All available image volumes will be loaded, if it is default or -% empty. -% -% dim5_idx (optional) - a numerical array of 5th dimension indices. -% Only the specified range will be loaded. All available range -% will be loaded, if it is default or empty. -% -% dim6_idx (optional) - a numerical array of 6th dimension indices. -% Only the specified range will be loaded. All available range -% will be loaded, if it is default or empty. -% -% dim7_idx (optional) - a numerical array of 7th dimension indices. -% Only the specified range will be loaded. All available range -% will be loaded, if it is default or empty. -% -% old_RGB (optional) - a scale number to tell difference of new RGB24 -% from old RGB24. New RGB24 uses RGB triple sequentially for each -% voxel, like [R1 G1 B1 R2 G2 B2 ...]. Analyze 6.0 from AnalyzeDirect -% uses old RGB24, in a way like [R1 R2 ... G1 G2 ... B1 B2 ...] for -% each slices. If the image that you view is garbled, try to set -% old_RGB variable to 1 and try again, because it could be in -% old RGB24. It will be set to 0, if it is default or empty. -% -% tolerance (optional) - distortion allowed in the loaded image for any -% non-orthogonal rotation or shearing of NIfTI affine matrix. If -% you set 'tolerance' to 0, it means that you do not allow any -% distortion. If you set 'tolerance' to 1, it means that you do -% not care any distortion. The image will fail to be loaded if it -% can not be tolerated. The tolerance will be set to 0.1 (10%), if -% it is default or empty. -% -% preferredForm (optional) - selects which transformation from voxels -% to RAS coordinates; values are s,q,S,Q. Lower case s,q indicate -% "prefer sform or qform, but use others if preferred not present". -% Upper case indicate the program is forced to use the specificied -% tranform or fail loading. 'preferredForm' will be 's', if it is -% default or empty. - Jeff Gunter -% -% Returned values: -% -% nii structure: -% -% hdr - struct with NIFTI header fields. -% -% filetype - Analyze format .hdr/.img (0); -% NIFTI .hdr/.img (1); -% NIFTI .nii (2) -% -% fileprefix - NIFTI filename without extension. -% -% machine - machine string variable. -% -% img - 3D (or 4D) matrix of NIFTI data. -% -% original - the original header before any affine transform. -% -% Part of this file is copied and modified from: -% http://www.mathworks.com/matlabcentral/fileexchange/1878-mri-analyze-tools -% -% NIFTI data format can be found on: http://nifti.nimh.nih.gov -% -% - Jimmy Shen (jimmy@rotman-baycrest.on.ca) -% -function nii = load_nii(filename, img_idx, dim5_idx, dim6_idx, dim7_idx, ... - old_RGB, tolerance, preferredForm) - - if ~exist('filename','var') - error('Usage: nii = load_nii(filename, [img_idx], [dim5_idx], [dim6_idx], [dim7_idx], [old_RGB], [tolerance], [preferredForm])'); - end - - if ~exist('img_idx','var') | isempty(img_idx) - img_idx = []; - end - - if ~exist('dim5_idx','var') | isempty(dim5_idx) - dim5_idx = []; - end - - if ~exist('dim6_idx','var') | isempty(dim6_idx) - dim6_idx = []; - end - - if ~exist('dim7_idx','var') | isempty(dim7_idx) - dim7_idx = []; - end - - if ~exist('old_RGB','var') | isempty(old_RGB) - old_RGB = 0; - end - - if ~exist('tolerance','var') | isempty(tolerance) - tolerance = 0.1; % 10 percent - end - - if ~exist('preferredForm','var') | isempty(preferredForm) - preferredForm= 's'; % Jeff - end - - % Read the dataset header - % - [nii.hdr,nii.filetype,nii.fileprefix,nii.machine] = load_nii_hdr(filename); - - % Read the header extension - % -% nii.ext = load_nii_ext(filename); - - % Read the dataset body - % - [nii.img,nii.hdr] = load_nii_img(nii.hdr,nii.filetype,nii.fileprefix, ... - nii.machine,img_idx,dim5_idx,dim6_idx,dim7_idx,old_RGB); - - % Perform some of sform/qform transform - % - nii = xform_nii(nii, tolerance, preferredForm); - - return % load_nii - +% Load NIFTI or ANALYZE dataset. Support both *.nii and *.hdr/*.img +% file extension. If file extension is not provided, *.hdr/*.img will +% be used as default. +% +% A subset of NIFTI transform is included. For non-orthogonal rotation, +% shearing etc., please use 'reslice_nii.m' to reslice the NIFTI file. +% It will not cause negative effect, as long as you remember not to do +% slice time correction after reslicing the NIFTI file. Output variable +% nii will be in RAS orientation, i.e. X axis from Left to Right, +% Y axis from Posterior to Anterior, and Z axis from Inferior to +% Superior. +% +% Usage: nii = load_nii(filename, [img_idx], [dim5_idx], [dim6_idx], ... +% [dim7_idx], [old_RGB], [tolerance], [preferredForm]) +% +% filename - NIFTI or ANALYZE file name. +% +% img_idx (optional) - a numerical array of 4th dimension indices, +% which is the indices of image scan volume. The number of images +% scan volumes can be obtained from get_nii_frame.m, or simply +% hdr.dime.dim(5). Only the specified volumes will be loaded. +% All available image volumes will be loaded, if it is default or +% empty. +% +% dim5_idx (optional) - a numerical array of 5th dimension indices. +% Only the specified range will be loaded. All available range +% will be loaded, if it is default or empty. +% +% dim6_idx (optional) - a numerical array of 6th dimension indices. +% Only the specified range will be loaded. All available range +% will be loaded, if it is default or empty. +% +% dim7_idx (optional) - a numerical array of 7th dimension indices. +% Only the specified range will be loaded. All available range +% will be loaded, if it is default or empty. +% +% old_RGB (optional) - a scale number to tell difference of new RGB24 +% from old RGB24. New RGB24 uses RGB triple sequentially for each +% voxel, like [R1 G1 B1 R2 G2 B2 ...]. Analyze 6.0 from AnalyzeDirect +% uses old RGB24, in a way like [R1 R2 ... G1 G2 ... B1 B2 ...] for +% each slices. If the image that you view is garbled, try to set +% old_RGB variable to 1 and try again, because it could be in +% old RGB24. It will be set to 0, if it is default or empty. +% +% tolerance (optional) - distortion allowed in the loaded image for any +% non-orthogonal rotation or shearing of NIfTI affine matrix. If +% you set 'tolerance' to 0, it means that you do not allow any +% distortion. If you set 'tolerance' to 1, it means that you do +% not care any distortion. The image will fail to be loaded if it +% can not be tolerated. The tolerance will be set to 0.1 (10%), if +% it is default or empty. +% +% preferredForm (optional) - selects which transformation from voxels +% to RAS coordinates; values are s,q,S,Q. Lower case s,q indicate +% "prefer sform or qform, but use others if preferred not present". +% Upper case indicate the program is forced to use the specificied +% tranform or fail loading. 'preferredForm' will be 's', if it is +% default or empty. - Jeff Gunter +% +% Returned values: +% +% nii structure: +% +% hdr - struct with NIFTI header fields. +% +% filetype - Analyze format .hdr/.img (0); +% NIFTI .hdr/.img (1); +% NIFTI .nii (2) +% +% fileprefix - NIFTI filename without extension. +% +% machine - machine string variable. +% +% img - 3D (or 4D) matrix of NIFTI data. +% +% original - the original header before any affine transform. +% +% Part of this file is copied and modified from: +% http://www.mathworks.com/matlabcentral/fileexchange/1878-mri-analyze-tools +% +% NIFTI data format can be found on: http://nifti.nimh.nih.gov +% +% - Jimmy Shen (jimmy@rotman-baycrest.on.ca) +% +function nii = load_nii(filename, img_idx, dim5_idx, dim6_idx, dim7_idx, ... + old_RGB, tolerance, preferredForm) + + if ~exist('filename','var') + error('Usage: nii = load_nii(filename, [img_idx], [dim5_idx], [dim6_idx], [dim7_idx], [old_RGB], [tolerance], [preferredForm])'); + end + + if ~exist('img_idx','var') | isempty(img_idx) + img_idx = []; + end + + if ~exist('dim5_idx','var') | isempty(dim5_idx) + dim5_idx = []; + end + + if ~exist('dim6_idx','var') | isempty(dim6_idx) + dim6_idx = []; + end + + if ~exist('dim7_idx','var') | isempty(dim7_idx) + dim7_idx = []; + end + + if ~exist('old_RGB','var') | isempty(old_RGB) + old_RGB = 0; + end + + if ~exist('tolerance','var') | isempty(tolerance) + tolerance = 0.1; % 10 percent + end + + if ~exist('preferredForm','var') | isempty(preferredForm) + preferredForm= 's'; % Jeff + end + + % Read the dataset header + % + [nii.hdr,nii.filetype,nii.fileprefix,nii.machine] = load_nii_hdr(filename); + + % Read the header extension + % +% nii.ext = load_nii_ext(filename); + + % Read the dataset body + % + [nii.img,nii.hdr] = load_nii_img(nii.hdr,nii.filetype,nii.fileprefix, ... + nii.machine,img_idx,dim5_idx,dim6_idx,dim7_idx,old_RGB); + + % Perform some of sform/qform transform + % + nii = xform_nii(nii, tolerance, preferredForm); + + return % load_nii + diff --git a/matlab/load_nii_ext.m b/matlab/load_nii_ext.m index 8077f1b..d0c171e 100644 --- a/matlab/load_nii_ext.m +++ b/matlab/load_nii_ext.m @@ -1,148 +1,148 @@ -% Load NIFTI header extension after its header is loaded using load_nii_hdr. -% -% Usage: ext = load_nii_ext(filename) -% -% filename - NIFTI file name. -% -% Returned values: -% -% ext - Structure of NIFTI header extension, which includes num_ext, -% and all the extended header sections in the header extension. -% Each extended header section will have its esize, ecode, and -% edata, where edata can be plain text, xml, or any raw data -% that was saved in the extended header section. -% -% NIFTI data format can be found on: http://nifti.nimh.nih.gov -% -% - Jimmy Shen (jimmy@rotman-baycrest.on.ca) -% -function ext = load_nii_ext(fileprefix) - - if ~exist('fileprefix','var'), - error('Usage: ext = load_nii_ext(filename)'); - end - - machine = 'ieee-le'; - new_ext = 0; - - if findstr('.nii',fileprefix) - new_ext = 1; - fileprefix = strrep(fileprefix,'.nii',''); - end - - if findstr('.hdr',fileprefix) - fileprefix = strrep(fileprefix,'.hdr',''); - end - - if findstr('.img',fileprefix) - fileprefix = strrep(fileprefix,'.img',''); - end - - if new_ext - fn = sprintf('%s.nii',fileprefix); - - if ~exist(fn) - msg = sprintf('Cannot find file "%s.nii".', fileprefix); - error(msg); - end - else - fn = sprintf('%s.hdr',fileprefix); - - if ~exist(fn) - msg = sprintf('Cannot find file "%s.hdr".', fileprefix); - error(msg); - end - end - - fid = fopen(fn,'r',machine); - vox_offset = 0; - - if fid < 0, - msg = sprintf('Cannot open file %s.',fn); - error(msg); - else - fseek(fid,0,'bof'); - - if fread(fid,1,'int32') == 348 - if new_ext - fseek(fid,108,'bof'); - vox_offset = fread(fid,1,'float32'); - end - - ext = read_extension(fid, vox_offset); - fclose(fid); - else - fclose(fid); - - % first try reading the opposite endian to 'machine' - % - switch machine, - case 'ieee-le', machine = 'ieee-be'; - case 'ieee-be', machine = 'ieee-le'; - end - - fid = fopen(fn,'r',machine); - - if fid < 0, - msg = sprintf('Cannot open file %s.',fn); - error(msg); - else - fseek(fid,0,'bof'); - - if fread(fid,1,'int32') ~= 348 - - % Now throw an error - % - msg = sprintf('File "%s" is corrupted.',fn); - error(msg); - end - - if new_ext - fseek(fid,108,'bof'); - vox_offset = fread(fid,1,'float32'); - end - - ext = read_extension(fid, vox_offset); - fclose(fid); - end - end - end - - return % load_nii_ext - - -%--------------------------------------------------------------------- -function ext = read_extension(fid, vox_offset) - - ext = []; - - if vox_offset - end_of_ext = vox_offset; - else - fseek(fid, 0, 'eof'); - end_of_ext = ftell(fid); - end - - if end_of_ext > 352 - fseek(fid, 348, 'bof'); - ext.extension = fread(fid,4)'; - end - - if isempty(ext) | ext.extension(1) == 0 - ext = []; - return; - end - - i = 1; - - while(ftell(fid) < end_of_ext) - ext.section(i).esize = fread(fid,1,'int32'); - ext.section(i).ecode = fread(fid,1,'int32'); - ext.section(i).edata = char(fread(fid,ext.section(i).esize-8)'); - i = i + 1; - end - - ext.num_ext = length(ext.section); - - return % read_extension - +% Load NIFTI header extension after its header is loaded using load_nii_hdr. +% +% Usage: ext = load_nii_ext(filename) +% +% filename - NIFTI file name. +% +% Returned values: +% +% ext - Structure of NIFTI header extension, which includes num_ext, +% and all the extended header sections in the header extension. +% Each extended header section will have its esize, ecode, and +% edata, where edata can be plain text, xml, or any raw data +% that was saved in the extended header section. +% +% NIFTI data format can be found on: http://nifti.nimh.nih.gov +% +% - Jimmy Shen (jimmy@rotman-baycrest.on.ca) +% +function ext = load_nii_ext(fileprefix) + + if ~exist('fileprefix','var'), + error('Usage: ext = load_nii_ext(filename)'); + end + + machine = 'ieee-le'; + new_ext = 0; + + if findstr('.nii',fileprefix) + new_ext = 1; + fileprefix = strrep(fileprefix,'.nii',''); + end + + if findstr('.hdr',fileprefix) + fileprefix = strrep(fileprefix,'.hdr',''); + end + + if findstr('.img',fileprefix) + fileprefix = strrep(fileprefix,'.img',''); + end + + if new_ext + fn = sprintf('%s.nii',fileprefix); + + if ~exist(fn) + msg = sprintf('Cannot find file "%s.nii".', fileprefix); + error(msg); + end + else + fn = sprintf('%s.hdr',fileprefix); + + if ~exist(fn) + msg = sprintf('Cannot find file "%s.hdr".', fileprefix); + error(msg); + end + end + + fid = fopen(fn,'r',machine); + vox_offset = 0; + + if fid < 0, + msg = sprintf('Cannot open file %s.',fn); + error(msg); + else + fseek(fid,0,'bof'); + + if fread(fid,1,'int32') == 348 + if new_ext + fseek(fid,108,'bof'); + vox_offset = fread(fid,1,'float32'); + end + + ext = read_extension(fid, vox_offset); + fclose(fid); + else + fclose(fid); + + % first try reading the opposite endian to 'machine' + % + switch machine, + case 'ieee-le', machine = 'ieee-be'; + case 'ieee-be', machine = 'ieee-le'; + end + + fid = fopen(fn,'r',machine); + + if fid < 0, + msg = sprintf('Cannot open file %s.',fn); + error(msg); + else + fseek(fid,0,'bof'); + + if fread(fid,1,'int32') ~= 348 + + % Now throw an error + % + msg = sprintf('File "%s" is corrupted.',fn); + error(msg); + end + + if new_ext + fseek(fid,108,'bof'); + vox_offset = fread(fid,1,'float32'); + end + + ext = read_extension(fid, vox_offset); + fclose(fid); + end + end + end + + return % load_nii_ext + + +%--------------------------------------------------------------------- +function ext = read_extension(fid, vox_offset) + + ext = []; + + if vox_offset + end_of_ext = vox_offset; + else + fseek(fid, 0, 'eof'); + end_of_ext = ftell(fid); + end + + if end_of_ext > 352 + fseek(fid, 348, 'bof'); + ext.extension = fread(fid,4)'; + end + + if isempty(ext) | ext.extension(1) == 0 + ext = []; + return; + end + + i = 1; + + while(ftell(fid) < end_of_ext) + ext.section(i).esize = fread(fid,1,'int32'); + ext.section(i).ecode = fread(fid,1,'int32'); + ext.section(i).edata = char(fread(fid,ext.section(i).esize-8)'); + i = i + 1; + end + + ext.num_ext = length(ext.section); + + return % read_extension + diff --git a/matlab/load_nii_hdr.m b/matlab/load_nii_hdr.m index e05eb1a..b73fd9a 100644 --- a/matlab/load_nii_hdr.m +++ b/matlab/load_nii_hdr.m @@ -1,280 +1,280 @@ -% internal function - -% - Jimmy Shen (jimmy@rotman-baycrest.on.ca) - -function [hdr, filetype, fileprefix, machine] = load_nii_hdr(fileprefix) - - if ~exist('fileprefix','var'), - error('Usage: [hdr, filetype, fileprefix, machine] = load_nii_hdr(filename)'); - end - - machine = 'ieee-le'; - new_ext = 0; - - if findstr('.nii',fileprefix) - new_ext = 1; - fileprefix = strrep(fileprefix,'.nii',''); - end - - if findstr('.hdr',fileprefix) - fileprefix = strrep(fileprefix,'.hdr',''); - end - - if findstr('.img',fileprefix) - fileprefix = strrep(fileprefix,'.img',''); - end - - if new_ext - fn = sprintf('%s.nii',fileprefix); - - if ~exist(fn) - msg = sprintf('Cannot find file "%s.nii".', fileprefix); - error(msg); - end - else - fn = sprintf('%s.hdr',fileprefix); - - if ~exist(fn) - msg = sprintf('Cannot find file "%s.hdr".', fileprefix); - error(msg); - end - end - - fid = fopen(fn,'r',machine); - - if fid < 0, - msg = sprintf('Cannot open file %s.',fn); - error(msg); - else - fseek(fid,0,'bof'); - - if fread(fid,1,'int32') == 348 - hdr = read_header(fid); - fclose(fid); - else - fclose(fid); - - % first try reading the opposite endian to 'machine' - % - switch machine, - case 'ieee-le', machine = 'ieee-be'; - case 'ieee-be', machine = 'ieee-le'; - end - - fid = fopen(fn,'r',machine); - - if fid < 0, - msg = sprintf('Cannot open file %s.',fn); - error(msg); - else - fseek(fid,0,'bof'); - - if fread(fid,1,'int32') ~= 348 - - % Now throw an error - % - msg = sprintf('File "%s" is corrupted.',fn); - error(msg); - end - - hdr = read_header(fid); - fclose(fid); - end - end - end - - if strcmp(hdr.hist.magic, 'n+1') - filetype = 2; - elseif strcmp(hdr.hist.magic, 'ni1') - filetype = 1; - else - filetype = 0; - end - - return % load_nii_hdr - - -%--------------------------------------------------------------------- -function [ dsr ] = read_header(fid) - - % Original header structures - % struct dsr - % { - % struct header_key hk; /* 0 + 40 */ - % struct image_dimension dime; /* 40 + 108 */ - % struct data_history hist; /* 148 + 200 */ - % }; /* total= 348 bytes*/ - - dsr.hk = header_key(fid); - dsr.dime = image_dimension(fid); - dsr.hist = data_history(fid); - - % For Analyze data format - % - if ~strcmp(dsr.hist.magic, 'n+1') & ~strcmp(dsr.hist.magic, 'ni1') - dsr.hist.qform_code = 0; - dsr.hist.sform_code = 0; - end - - return % read_header - - -%--------------------------------------------------------------------- -function [ hk ] = header_key(fid) - - fseek(fid,0,'bof'); - - % Original header structures - % struct header_key /* header key */ - % { /* off + size */ - % int sizeof_hdr /* 0 + 4 */ - % char data_type[10]; /* 4 + 10 */ - % char db_name[18]; /* 14 + 18 */ - % int extents; /* 32 + 4 */ - % short int session_error; /* 36 + 2 */ - % char regular; /* 38 + 1 */ - % char dim_info; % char hkey_un0; /* 39 + 1 */ - % }; /* total=40 bytes */ - % - % int sizeof_header Should be 348. - % char regular Must be 'r' to indicate that all images and - % volumes are the same size. - - v6 = version; - if str2num(v6(1))<6 - directchar = '*char'; - else - directchar = 'uchar=>char'; - end - - hk.sizeof_hdr = fread(fid, 1,'int32')'; % should be 348! - hk.data_type = deblank(fread(fid,10,directchar)'); - hk.db_name = deblank(fread(fid,18,directchar)'); - hk.extents = fread(fid, 1,'int32')'; - hk.session_error = fread(fid, 1,'int16')'; - hk.regular = fread(fid, 1,directchar)'; - hk.dim_info = fread(fid, 1,'uchar')'; - - return % header_key - - -%--------------------------------------------------------------------- -function [ dime ] = image_dimension(fid) - - % Original header structures - % struct image_dimension - % { /* off + size */ - % short int dim[8]; /* 0 + 16 */ - % /* - % dim[0] Number of dimensions in database; usually 4. - % dim[1] Image X dimension; number of *pixels* in an image row. - % dim[2] Image Y dimension; number of *pixel rows* in slice. - % dim[3] Volume Z dimension; number of *slices* in a volume. - % dim[4] Time points; number of volumes in database - % */ - % float intent_p1; % char vox_units[4]; /* 16 + 4 */ - % float intent_p2; % char cal_units[8]; /* 20 + 4 */ - % float intent_p3; % char cal_units[8]; /* 24 + 4 */ - % short int intent_code; % short int unused1; /* 28 + 2 */ - % short int datatype; /* 30 + 2 */ - % short int bitpix; /* 32 + 2 */ - % short int slice_start; % short int dim_un0; /* 34 + 2 */ - % float pixdim[8]; /* 36 + 32 */ - % /* - % pixdim[] specifies the voxel dimensions: - % pixdim[1] - voxel width, mm - % pixdim[2] - voxel height, mm - % pixdim[3] - slice thickness, mm - % pixdim[4] - volume timing, in msec - % ..etc - % */ - % float vox_offset; /* 68 + 4 */ - % float scl_slope; % float roi_scale; /* 72 + 4 */ - % float scl_inter; % float funused1; /* 76 + 4 */ - % short slice_end; % float funused2; /* 80 + 2 */ - % char slice_code; % float funused2; /* 82 + 1 */ - % char xyzt_units; % float funused2; /* 83 + 1 */ - % float cal_max; /* 84 + 4 */ - % float cal_min; /* 88 + 4 */ - % float slice_duration; % int compressed; /* 92 + 4 */ - % float toffset; % int verified; /* 96 + 4 */ - % int glmax; /* 100 + 4 */ - % int glmin; /* 104 + 4 */ - % }; /* total=108 bytes */ - - dime.dim = fread(fid,8,'int16')'; - dime.intent_p1 = fread(fid,1,'float32')'; - dime.intent_p2 = fread(fid,1,'float32')'; - dime.intent_p3 = fread(fid,1,'float32')'; - dime.intent_code = fread(fid,1,'int16')'; - dime.datatype = fread(fid,1,'int16')'; - dime.bitpix = fread(fid,1,'int16')'; - dime.slice_start = fread(fid,1,'int16')'; - dime.pixdim = fread(fid,8,'float32')'; - dime.vox_offset = fread(fid,1,'float32')'; - dime.scl_slope = fread(fid,1,'float32')'; - dime.scl_inter = fread(fid,1,'float32')'; - dime.slice_end = fread(fid,1,'int16')'; - dime.slice_code = fread(fid,1,'uchar')'; - dime.xyzt_units = fread(fid,1,'uchar')'; - dime.cal_max = fread(fid,1,'float32')'; - dime.cal_min = fread(fid,1,'float32')'; - dime.slice_duration = fread(fid,1,'float32')'; - dime.toffset = fread(fid,1,'float32')'; - dime.glmax = fread(fid,1,'int32')'; - dime.glmin = fread(fid,1,'int32')'; - - return % image_dimension - - -%--------------------------------------------------------------------- -function [ hist ] = data_history(fid) - - % Original header structures - % struct data_history - % { /* off + size */ - % char descrip[80]; /* 0 + 80 */ - % char aux_file[24]; /* 80 + 24 */ - % short int qform_code; /* 104 + 2 */ - % short int sform_code; /* 106 + 2 */ - % float quatern_b; /* 108 + 4 */ - % float quatern_c; /* 112 + 4 */ - % float quatern_d; /* 116 + 4 */ - % float qoffset_x; /* 120 + 4 */ - % float qoffset_y; /* 124 + 4 */ - % float qoffset_z; /* 128 + 4 */ - % float srow_x[4]; /* 132 + 16 */ - % float srow_y[4]; /* 148 + 16 */ - % float srow_z[4]; /* 164 + 16 */ - % char intent_name[16]; /* 180 + 16 */ - % char magic[4]; % int smin; /* 196 + 4 */ - % }; /* total=200 bytes */ - - v6 = version; - if str2num(v6(1))<6 - directchar = '*char'; - else - directchar = 'uchar=>char'; - end - - hist.descrip = deblank(fread(fid,80,directchar)'); - hist.aux_file = deblank(fread(fid,24,directchar)'); - hist.qform_code = fread(fid,1,'int16')'; - hist.sform_code = fread(fid,1,'int16')'; - hist.quatern_b = fread(fid,1,'float32')'; - hist.quatern_c = fread(fid,1,'float32')'; - hist.quatern_d = fread(fid,1,'float32')'; - hist.qoffset_x = fread(fid,1,'float32')'; - hist.qoffset_y = fread(fid,1,'float32')'; - hist.qoffset_z = fread(fid,1,'float32')'; - hist.srow_x = fread(fid,4,'float32')'; - hist.srow_y = fread(fid,4,'float32')'; - hist.srow_z = fread(fid,4,'float32')'; - hist.intent_name = deblank(fread(fid,16,directchar)'); - hist.magic = deblank(fread(fid,4,directchar)'); - - fseek(fid,253,'bof'); - hist.originator = fread(fid, 5,'int16')'; - - return % data_history - +% internal function + +% - Jimmy Shen (jimmy@rotman-baycrest.on.ca) + +function [hdr, filetype, fileprefix, machine] = load_nii_hdr(fileprefix) + + if ~exist('fileprefix','var'), + error('Usage: [hdr, filetype, fileprefix, machine] = load_nii_hdr(filename)'); + end + + machine = 'ieee-le'; + new_ext = 0; + + if findstr('.nii',fileprefix) + new_ext = 1; + fileprefix = strrep(fileprefix,'.nii',''); + end + + if findstr('.hdr',fileprefix) + fileprefix = strrep(fileprefix,'.hdr',''); + end + + if findstr('.img',fileprefix) + fileprefix = strrep(fileprefix,'.img',''); + end + + if new_ext + fn = sprintf('%s.nii',fileprefix); + + if ~exist(fn) + msg = sprintf('Cannot find file "%s.nii".', fileprefix); + error(msg); + end + else + fn = sprintf('%s.hdr',fileprefix); + + if ~exist(fn) + msg = sprintf('Cannot find file "%s.hdr".', fileprefix); + error(msg); + end + end + + fid = fopen(fn,'r',machine); + + if fid < 0, + msg = sprintf('Cannot open file %s.',fn); + error(msg); + else + fseek(fid,0,'bof'); + + if fread(fid,1,'int32') == 348 + hdr = read_header(fid); + fclose(fid); + else + fclose(fid); + + % first try reading the opposite endian to 'machine' + % + switch machine, + case 'ieee-le', machine = 'ieee-be'; + case 'ieee-be', machine = 'ieee-le'; + end + + fid = fopen(fn,'r',machine); + + if fid < 0, + msg = sprintf('Cannot open file %s.',fn); + error(msg); + else + fseek(fid,0,'bof'); + + if fread(fid,1,'int32') ~= 348 + + % Now throw an error + % + msg = sprintf('File "%s" is corrupted.',fn); + error(msg); + end + + hdr = read_header(fid); + fclose(fid); + end + end + end + + if strcmp(hdr.hist.magic, 'n+1') + filetype = 2; + elseif strcmp(hdr.hist.magic, 'ni1') + filetype = 1; + else + filetype = 0; + end + + return % load_nii_hdr + + +%--------------------------------------------------------------------- +function [ dsr ] = read_header(fid) + + % Original header structures + % struct dsr + % { + % struct header_key hk; /* 0 + 40 */ + % struct image_dimension dime; /* 40 + 108 */ + % struct data_history hist; /* 148 + 200 */ + % }; /* total= 348 bytes*/ + + dsr.hk = header_key(fid); + dsr.dime = image_dimension(fid); + dsr.hist = data_history(fid); + + % For Analyze data format + % + if ~strcmp(dsr.hist.magic, 'n+1') & ~strcmp(dsr.hist.magic, 'ni1') + dsr.hist.qform_code = 0; + dsr.hist.sform_code = 0; + end + + return % read_header + + +%--------------------------------------------------------------------- +function [ hk ] = header_key(fid) + + fseek(fid,0,'bof'); + + % Original header structures + % struct header_key /* header key */ + % { /* off + size */ + % int sizeof_hdr /* 0 + 4 */ + % char data_type[10]; /* 4 + 10 */ + % char db_name[18]; /* 14 + 18 */ + % int extents; /* 32 + 4 */ + % short int session_error; /* 36 + 2 */ + % char regular; /* 38 + 1 */ + % char dim_info; % char hkey_un0; /* 39 + 1 */ + % }; /* total=40 bytes */ + % + % int sizeof_header Should be 348. + % char regular Must be 'r' to indicate that all images and + % volumes are the same size. + + v6 = version; + if str2num(v6(1))<6 + directchar = '*char'; + else + directchar = 'uchar=>char'; + end + + hk.sizeof_hdr = fread(fid, 1,'int32')'; % should be 348! + hk.data_type = deblank(fread(fid,10,directchar)'); + hk.db_name = deblank(fread(fid,18,directchar)'); + hk.extents = fread(fid, 1,'int32')'; + hk.session_error = fread(fid, 1,'int16')'; + hk.regular = fread(fid, 1,directchar)'; + hk.dim_info = fread(fid, 1,'uchar')'; + + return % header_key + + +%--------------------------------------------------------------------- +function [ dime ] = image_dimension(fid) + + % Original header structures + % struct image_dimension + % { /* off + size */ + % short int dim[8]; /* 0 + 16 */ + % /* + % dim[0] Number of dimensions in database; usually 4. + % dim[1] Image X dimension; number of *pixels* in an image row. + % dim[2] Image Y dimension; number of *pixel rows* in slice. + % dim[3] Volume Z dimension; number of *slices* in a volume. + % dim[4] Time points; number of volumes in database + % */ + % float intent_p1; % char vox_units[4]; /* 16 + 4 */ + % float intent_p2; % char cal_units[8]; /* 20 + 4 */ + % float intent_p3; % char cal_units[8]; /* 24 + 4 */ + % short int intent_code; % short int unused1; /* 28 + 2 */ + % short int datatype; /* 30 + 2 */ + % short int bitpix; /* 32 + 2 */ + % short int slice_start; % short int dim_un0; /* 34 + 2 */ + % float pixdim[8]; /* 36 + 32 */ + % /* + % pixdim[] specifies the voxel dimensions: + % pixdim[1] - voxel width, mm + % pixdim[2] - voxel height, mm + % pixdim[3] - slice thickness, mm + % pixdim[4] - volume timing, in msec + % ..etc + % */ + % float vox_offset; /* 68 + 4 */ + % float scl_slope; % float roi_scale; /* 72 + 4 */ + % float scl_inter; % float funused1; /* 76 + 4 */ + % short slice_end; % float funused2; /* 80 + 2 */ + % char slice_code; % float funused2; /* 82 + 1 */ + % char xyzt_units; % float funused2; /* 83 + 1 */ + % float cal_max; /* 84 + 4 */ + % float cal_min; /* 88 + 4 */ + % float slice_duration; % int compressed; /* 92 + 4 */ + % float toffset; % int verified; /* 96 + 4 */ + % int glmax; /* 100 + 4 */ + % int glmin; /* 104 + 4 */ + % }; /* total=108 bytes */ + + dime.dim = fread(fid,8,'int16')'; + dime.intent_p1 = fread(fid,1,'float32')'; + dime.intent_p2 = fread(fid,1,'float32')'; + dime.intent_p3 = fread(fid,1,'float32')'; + dime.intent_code = fread(fid,1,'int16')'; + dime.datatype = fread(fid,1,'int16')'; + dime.bitpix = fread(fid,1,'int16')'; + dime.slice_start = fread(fid,1,'int16')'; + dime.pixdim = fread(fid,8,'float32')'; + dime.vox_offset = fread(fid,1,'float32')'; + dime.scl_slope = fread(fid,1,'float32')'; + dime.scl_inter = fread(fid,1,'float32')'; + dime.slice_end = fread(fid,1,'int16')'; + dime.slice_code = fread(fid,1,'uchar')'; + dime.xyzt_units = fread(fid,1,'uchar')'; + dime.cal_max = fread(fid,1,'float32')'; + dime.cal_min = fread(fid,1,'float32')'; + dime.slice_duration = fread(fid,1,'float32')'; + dime.toffset = fread(fid,1,'float32')'; + dime.glmax = fread(fid,1,'int32')'; + dime.glmin = fread(fid,1,'int32')'; + + return % image_dimension + + +%--------------------------------------------------------------------- +function [ hist ] = data_history(fid) + + % Original header structures + % struct data_history + % { /* off + size */ + % char descrip[80]; /* 0 + 80 */ + % char aux_file[24]; /* 80 + 24 */ + % short int qform_code; /* 104 + 2 */ + % short int sform_code; /* 106 + 2 */ + % float quatern_b; /* 108 + 4 */ + % float quatern_c; /* 112 + 4 */ + % float quatern_d; /* 116 + 4 */ + % float qoffset_x; /* 120 + 4 */ + % float qoffset_y; /* 124 + 4 */ + % float qoffset_z; /* 128 + 4 */ + % float srow_x[4]; /* 132 + 16 */ + % float srow_y[4]; /* 148 + 16 */ + % float srow_z[4]; /* 164 + 16 */ + % char intent_name[16]; /* 180 + 16 */ + % char magic[4]; % int smin; /* 196 + 4 */ + % }; /* total=200 bytes */ + + v6 = version; + if str2num(v6(1))<6 + directchar = '*char'; + else + directchar = 'uchar=>char'; + end + + hist.descrip = deblank(fread(fid,80,directchar)'); + hist.aux_file = deblank(fread(fid,24,directchar)'); + hist.qform_code = fread(fid,1,'int16')'; + hist.sform_code = fread(fid,1,'int16')'; + hist.quatern_b = fread(fid,1,'float32')'; + hist.quatern_c = fread(fid,1,'float32')'; + hist.quatern_d = fread(fid,1,'float32')'; + hist.qoffset_x = fread(fid,1,'float32')'; + hist.qoffset_y = fread(fid,1,'float32')'; + hist.qoffset_z = fread(fid,1,'float32')'; + hist.srow_x = fread(fid,4,'float32')'; + hist.srow_y = fread(fid,4,'float32')'; + hist.srow_z = fread(fid,4,'float32')'; + hist.intent_name = deblank(fread(fid,16,directchar)'); + hist.magic = deblank(fread(fid,4,directchar)'); + + fseek(fid,253,'bof'); + hist.originator = fread(fid, 5,'int16')'; + + return % data_history + diff --git a/matlab/load_nii_img.m b/matlab/load_nii_img.m index f6e7b5d..60adb7d 100644 --- a/matlab/load_nii_img.m +++ b/matlab/load_nii_img.m @@ -1,392 +1,392 @@ -% internal function - -% - Jimmy Shen (jimmy@rotman-baycrest.on.ca) - -function [img,hdr] = load_nii_img(hdr,filetype,fileprefix,machine,img_idx,dim5_idx,dim6_idx,dim7_idx,old_RGB) - - if ~exist('hdr','var') | ~exist('filetype','var') | ~exist('fileprefix','var') | ~exist('machine','var') - error('Usage: [img,hdr] = load_nii_img(hdr,filetype,fileprefix,machine,[img_idx],[dim5_idx],[dim6_idx],[dim7_idx],[old_RGB]);'); - end - - if ~exist('img_idx','var') | isempty(img_idx) | hdr.dime.dim(5)<1 - img_idx = []; - end - - if ~exist('dim5_idx','var') | isempty(dim5_idx) | hdr.dime.dim(6)<1 - dim5_idx = []; - end - - if ~exist('dim6_idx','var') | isempty(dim6_idx) | hdr.dime.dim(7)<1 - dim6_idx = []; - end - - if ~exist('dim7_idx','var') | isempty(dim7_idx) | hdr.dime.dim(8)<1 - dim7_idx = []; - end - - if ~exist('old_RGB','var') | isempty(old_RGB) - old_RGB = 0; - end - - % check img_idx - % - if ~isempty(img_idx) & ~isnumeric(img_idx) - error('"img_idx" should be a numerical array.'); - end - - if length(unique(img_idx)) ~= length(img_idx) - error('Duplicate image index in "img_idx"'); - end - - if ~isempty(img_idx) & (min(img_idx) < 1 | max(img_idx) > hdr.dime.dim(5)) - max_range = hdr.dime.dim(5); - - if max_range == 1 - error(['"img_idx" should be 1.']); - else - range = ['1 ' num2str(max_range)]; - error(['"img_idx" should be an integer within the range of [' range '].']); - end - end - - % check dim5_idx - % - if ~isempty(dim5_idx) & ~isnumeric(dim5_idx) - error('"dim5_idx" should be a numerical array.'); - end - - if length(unique(dim5_idx)) ~= length(dim5_idx) - error('Duplicate index in "dim5_idx"'); - end - - if ~isempty(dim5_idx) & (min(dim5_idx) < 1 | max(dim5_idx) > hdr.dime.dim(6)) - max_range = hdr.dime.dim(6); - - if max_range == 1 - error(['"dim5_idx" should be 1.']); - else - range = ['1 ' num2str(max_range)]; - error(['"dim5_idx" should be an integer within the range of [' range '].']); - end - end - - % check dim6_idx - % - if ~isempty(dim6_idx) & ~isnumeric(dim6_idx) - error('"dim6_idx" should be a numerical array.'); - end - - if length(unique(dim6_idx)) ~= length(dim6_idx) - error('Duplicate index in "dim6_idx"'); - end - - if ~isempty(dim6_idx) & (min(dim6_idx) < 1 | max(dim6_idx) > hdr.dime.dim(7)) - max_range = hdr.dime.dim(7); - - if max_range == 1 - error(['"dim6_idx" should be 1.']); - else - range = ['1 ' num2str(max_range)]; - error(['"dim6_idx" should be an integer within the range of [' range '].']); - end - end - - % check dim7_idx - % - if ~isempty(dim7_idx) & ~isnumeric(dim7_idx) - error('"dim7_idx" should be a numerical array.'); - end - - if length(unique(dim7_idx)) ~= length(dim7_idx) - error('Duplicate index in "dim7_idx"'); - end - - if ~isempty(dim7_idx) & (min(dim7_idx) < 1 | max(dim7_idx) > hdr.dime.dim(8)) - max_range = hdr.dime.dim(8); - - if max_range == 1 - error(['"dim7_idx" should be 1.']); - else - range = ['1 ' num2str(max_range)]; - error(['"dim7_idx" should be an integer within the range of [' range '].']); - end - end - - [img,hdr] = read_image(hdr,filetype,fileprefix,machine,img_idx,dim5_idx,dim6_idx,dim7_idx,old_RGB); - - return % load_nii_img - - -%--------------------------------------------------------------------- -function [img,hdr] = read_image(hdr,filetype,fileprefix,machine,img_idx,dim5_idx,dim6_idx,dim7_idx,old_RGB) - - switch filetype - case {0, 1} - fn = [fileprefix '.img']; - case 2 - fn = [fileprefix '.nii']; - end - - fid = fopen(fn,'r',machine); - - if fid < 0, - msg = sprintf('Cannot open file %s.',fn); - error(msg); - end - - % Set bitpix according to datatype - % - % /*Acceptable values for datatype are*/ - % - % 0 None (Unknown bit per voxel) % DT_NONE, DT_UNKNOWN - % 1 Binary (ubit1, bitpix=1) % DT_BINARY - % 2 Unsigned char (uchar or uint8, bitpix=8) % DT_UINT8, NIFTI_TYPE_UINT8 - % 4 Signed short (int16, bitpix=16) % DT_INT16, NIFTI_TYPE_INT16 - % 8 Signed integer (int32, bitpix=32) % DT_INT32, NIFTI_TYPE_INT32 - % 16 Floating point (single or float32, bitpix=32) % DT_FLOAT32, NIFTI_TYPE_FLOAT32 - % 32 Complex, 2 float32 (Use float32, bitpix=64) % DT_COMPLEX64, NIFTI_TYPE_COMPLEX64 - % 64 Double precision (double or float64, bitpix=64) % DT_FLOAT64, NIFTI_TYPE_FLOAT64 - % 128 uint8 RGB (Use uint8, bitpix=24) % DT_RGB24, NIFTI_TYPE_RGB24 - % 256 Signed char (schar or int8, bitpix=8) % DT_INT8, NIFTI_TYPE_INT8 - % 511 Single RGB (Use float32, bitpix=96) % DT_RGB96, NIFTI_TYPE_RGB96 - % 512 Unsigned short (uint16, bitpix=16) % DT_UNINT16, NIFTI_TYPE_UNINT16 - % 768 Unsigned integer (uint32, bitpix=32) % DT_UNINT32, NIFTI_TYPE_UNINT32 - % 1024 Signed long long (int64, bitpix=64) % DT_INT64, NIFTI_TYPE_INT64 - % 1280 Unsigned long long (uint64, bitpix=64) % DT_UINT64, NIFTI_TYPE_UINT64 - % 1536 Long double, float128 (Unsupported, bitpix=128) % DT_FLOAT128, NIFTI_TYPE_FLOAT128 - % 1792 Complex128, 2 float64 (Use float64, bitpix=128) % DT_COMPLEX128, NIFTI_TYPE_COMPLEX128 - % 2048 Complex256, 2 float128 (Unsupported, bitpix=256) % DT_COMPLEX128, NIFTI_TYPE_COMPLEX128 - % - switch hdr.dime.datatype - case 1, - hdr.dime.bitpix = 1; precision = 'ubit1'; - case 2, - hdr.dime.bitpix = 8; precision = 'uint8'; - case 4, - hdr.dime.bitpix = 16; precision = 'int16'; - case 8, - hdr.dime.bitpix = 32; precision = 'int32'; - case 16, - hdr.dime.bitpix = 32; precision = 'float32'; - case 32, - hdr.dime.bitpix = 64; precision = 'float32'; - case 64, - hdr.dime.bitpix = 64; precision = 'float64'; - case 128, - hdr.dime.bitpix = 24; precision = 'uint8'; - case 256 - hdr.dime.bitpix = 8; precision = 'int8'; - case 511 - hdr.dime.bitpix = 96; precision = 'float32'; - case 512 - hdr.dime.bitpix = 16; precision = 'uint16'; - case 768 - hdr.dime.bitpix = 32; precision = 'uint32'; - case 1024 - hdr.dime.bitpix = 64; precision = 'int64'; - case 1280 - hdr.dime.bitpix = 64; precision = 'uint64'; - case 1792, - hdr.dime.bitpix = 128; precision = 'float64'; - otherwise - error('This datatype is not supported'); - end - - hdr.dime.dim(find(hdr.dime.dim < 1)) = 1; - - % move pointer to the start of image block - % - switch filetype - case {0, 1} - fseek(fid, 0, 'bof'); - case 2 - fseek(fid, hdr.dime.vox_offset, 'bof'); - end - - % Load whole image block for old Analyze format or binary image; - % otherwise, load images that are specified in img_idx, dim5_idx, - % dim6_idx, and dim7_idx - % - % For binary image, we have to read all because pos can not be - % seeked in bit and can not be calculated the way below. - % - if hdr.dime.datatype == 1 | isequal(hdr.dime.dim(5:8),ones(1,4)) | ... - (isempty(img_idx) & isempty(dim5_idx) & isempty(dim6_idx) & isempty(dim7_idx)) - - % For each frame, precision of value will be read - % in img_siz times, where img_siz is only the - % dimension size of an image, not the byte storage - % size of an image. - % - img_siz = prod(hdr.dime.dim(2:8)); - - % For complex float32 or complex float64, voxel values - % include [real, imag] - % - if hdr.dime.datatype == 32 | hdr.dime.datatype == 1792 - img_siz = img_siz * 2; - end - - %MPH: For RGB24, voxel values include 3 separate color planes - % - if hdr.dime.datatype == 128 | hdr.dime.datatype == 511 - img_siz = img_siz * 3; - end - - img = fread(fid, img_siz, sprintf('*%s',precision)); - - d1 = hdr.dime.dim(2); - d2 = hdr.dime.dim(3); - d3 = hdr.dime.dim(4); - d4 = hdr.dime.dim(5); - d5 = hdr.dime.dim(6); - d6 = hdr.dime.dim(7); - d7 = hdr.dime.dim(8); - - if isempty(img_idx) - img_idx = 1:d4; - end - - if isempty(dim5_idx) - dim5_idx = 1:d5; - end - - if isempty(dim6_idx) - dim6_idx = 1:d6; - end - - if isempty(dim7_idx) - dim7_idx = 1:d7; - end - else - - d1 = hdr.dime.dim(2); - d2 = hdr.dime.dim(3); - d3 = hdr.dime.dim(4); - d4 = hdr.dime.dim(5); - d5 = hdr.dime.dim(6); - d6 = hdr.dime.dim(7); - d7 = hdr.dime.dim(8); - - if isempty(img_idx) - img_idx = 1:d4; - end - - if isempty(dim5_idx) - dim5_idx = 1:d5; - end - - if isempty(dim6_idx) - dim6_idx = 1:d6; - end - - if isempty(dim7_idx) - dim7_idx = 1:d7; - end - - % compute size of one image - % - img_siz = prod(hdr.dime.dim(2:4)); - - % For complex float32 or complex float64, voxel values - % include [real, imag] - % - if hdr.dime.datatype == 32 | hdr.dime.datatype == 1792 - img_siz = img_siz * 2; - end - - %MPH: For RGB24, voxel values include 3 separate color planes - % - if hdr.dime.datatype == 128 | hdr.dime.datatype == 511 - img_siz = img_siz * 3; - end - - % preallocate img - img = zeros(img_siz, length(img_idx)*length(dim5_idx)*length(dim6_idx)*length(dim7_idx) ); - currentIndex = 1; - - for i7=1:length(dim7_idx) - for i6=1:length(dim6_idx) - for i5=1:length(dim5_idx) - for t=1:length(img_idx) - - % Position is seeked in bytes. To convert dimension size - % to byte storage size, hdr.dime.bitpix/8 will be - % applied. - % - pos = sub2ind([d1 d2 d3 d4 d5 d6 d7], 1, 1, 1, ... - img_idx(t), dim5_idx(i5),dim6_idx(i6),dim7_idx(i7)) -1; - pos = pos * hdr.dime.bitpix/8; - - if filetype == 2 - fseek(fid, pos + hdr.dime.vox_offset, 'bof'); - else - fseek(fid, pos, 'bof'); - end - - % For each frame, fread will read precision of value - % in img_siz times - % - img(:,currentIndex) = fread(fid, img_siz, sprintf('*%s',precision)); - currentIndex = currentIndex +1; - - end - end - end - end - end - - % For complex float32 or complex float64, voxel values - % include [real, imag] - % - if hdr.dime.datatype == 32 | hdr.dime.datatype == 1792 - img = reshape(img, [2, length(img)/2]); - img = complex(img(1,:)', img(2,:)'); - end - - fclose(fid); - - % Update the global min and max values - % - hdr.dime.glmax = double(max(img(:))); - hdr.dime.glmin = double(min(img(:))); - - % old_RGB treat RGB slice by slice, now it is treated voxel by voxel - % - if old_RGB & hdr.dime.datatype == 128 & hdr.dime.bitpix == 24 - % remove squeeze - img = (reshape(img, [hdr.dime.dim(2:3) 3 hdr.dime.dim(4) length(img_idx) length(dim5_idx) length(dim6_idx) length(dim7_idx)])); - img = permute(img, [1 2 4 3 5 6 7 8]); - elseif hdr.dime.datatype == 128 & hdr.dime.bitpix == 24 - % remove squeeze - img = (reshape(img, [3 hdr.dime.dim(2:4) length(img_idx) length(dim5_idx) length(dim6_idx) length(dim7_idx)])); - img = permute(img, [2 3 4 1 5 6 7 8]); - elseif hdr.dime.datatype == 511 & hdr.dime.bitpix == 96 - img = double(img(:)); - img = single((img - min(img))/(max(img) - min(img))); - % remove squeeze - img = (reshape(img, [3 hdr.dime.dim(2:4) length(img_idx) length(dim5_idx) length(dim6_idx) length(dim7_idx)])); - img = permute(img, [2 3 4 1 5 6 7 8]); - else - % remove squeeze - img = (reshape(img, [hdr.dime.dim(2:4) length(img_idx) length(dim5_idx) length(dim6_idx) length(dim7_idx)])); - end - - if ~isempty(img_idx) - hdr.dime.dim(5) = length(img_idx); - end - - if ~isempty(dim5_idx) - hdr.dime.dim(6) = length(dim5_idx); - end - - if ~isempty(dim6_idx) - hdr.dime.dim(7) = length(dim6_idx); - end - - if ~isempty(dim7_idx) - hdr.dime.dim(8) = length(dim7_idx); - end - - return % read_image - +% internal function + +% - Jimmy Shen (jimmy@rotman-baycrest.on.ca) + +function [img,hdr] = load_nii_img(hdr,filetype,fileprefix,machine,img_idx,dim5_idx,dim6_idx,dim7_idx,old_RGB) + + if ~exist('hdr','var') | ~exist('filetype','var') | ~exist('fileprefix','var') | ~exist('machine','var') + error('Usage: [img,hdr] = load_nii_img(hdr,filetype,fileprefix,machine,[img_idx],[dim5_idx],[dim6_idx],[dim7_idx],[old_RGB]);'); + end + + if ~exist('img_idx','var') | isempty(img_idx) | hdr.dime.dim(5)<1 + img_idx = []; + end + + if ~exist('dim5_idx','var') | isempty(dim5_idx) | hdr.dime.dim(6)<1 + dim5_idx = []; + end + + if ~exist('dim6_idx','var') | isempty(dim6_idx) | hdr.dime.dim(7)<1 + dim6_idx = []; + end + + if ~exist('dim7_idx','var') | isempty(dim7_idx) | hdr.dime.dim(8)<1 + dim7_idx = []; + end + + if ~exist('old_RGB','var') | isempty(old_RGB) + old_RGB = 0; + end + + % check img_idx + % + if ~isempty(img_idx) & ~isnumeric(img_idx) + error('"img_idx" should be a numerical array.'); + end + + if length(unique(img_idx)) ~= length(img_idx) + error('Duplicate image index in "img_idx"'); + end + + if ~isempty(img_idx) & (min(img_idx) < 1 | max(img_idx) > hdr.dime.dim(5)) + max_range = hdr.dime.dim(5); + + if max_range == 1 + error(['"img_idx" should be 1.']); + else + range = ['1 ' num2str(max_range)]; + error(['"img_idx" should be an integer within the range of [' range '].']); + end + end + + % check dim5_idx + % + if ~isempty(dim5_idx) & ~isnumeric(dim5_idx) + error('"dim5_idx" should be a numerical array.'); + end + + if length(unique(dim5_idx)) ~= length(dim5_idx) + error('Duplicate index in "dim5_idx"'); + end + + if ~isempty(dim5_idx) & (min(dim5_idx) < 1 | max(dim5_idx) > hdr.dime.dim(6)) + max_range = hdr.dime.dim(6); + + if max_range == 1 + error(['"dim5_idx" should be 1.']); + else + range = ['1 ' num2str(max_range)]; + error(['"dim5_idx" should be an integer within the range of [' range '].']); + end + end + + % check dim6_idx + % + if ~isempty(dim6_idx) & ~isnumeric(dim6_idx) + error('"dim6_idx" should be a numerical array.'); + end + + if length(unique(dim6_idx)) ~= length(dim6_idx) + error('Duplicate index in "dim6_idx"'); + end + + if ~isempty(dim6_idx) & (min(dim6_idx) < 1 | max(dim6_idx) > hdr.dime.dim(7)) + max_range = hdr.dime.dim(7); + + if max_range == 1 + error(['"dim6_idx" should be 1.']); + else + range = ['1 ' num2str(max_range)]; + error(['"dim6_idx" should be an integer within the range of [' range '].']); + end + end + + % check dim7_idx + % + if ~isempty(dim7_idx) & ~isnumeric(dim7_idx) + error('"dim7_idx" should be a numerical array.'); + end + + if length(unique(dim7_idx)) ~= length(dim7_idx) + error('Duplicate index in "dim7_idx"'); + end + + if ~isempty(dim7_idx) & (min(dim7_idx) < 1 | max(dim7_idx) > hdr.dime.dim(8)) + max_range = hdr.dime.dim(8); + + if max_range == 1 + error(['"dim7_idx" should be 1.']); + else + range = ['1 ' num2str(max_range)]; + error(['"dim7_idx" should be an integer within the range of [' range '].']); + end + end + + [img,hdr] = read_image(hdr,filetype,fileprefix,machine,img_idx,dim5_idx,dim6_idx,dim7_idx,old_RGB); + + return % load_nii_img + + +%--------------------------------------------------------------------- +function [img,hdr] = read_image(hdr,filetype,fileprefix,machine,img_idx,dim5_idx,dim6_idx,dim7_idx,old_RGB) + + switch filetype + case {0, 1} + fn = [fileprefix '.img']; + case 2 + fn = [fileprefix '.nii']; + end + + fid = fopen(fn,'r',machine); + + if fid < 0, + msg = sprintf('Cannot open file %s.',fn); + error(msg); + end + + % Set bitpix according to datatype + % + % /*Acceptable values for datatype are*/ + % + % 0 None (Unknown bit per voxel) % DT_NONE, DT_UNKNOWN + % 1 Binary (ubit1, bitpix=1) % DT_BINARY + % 2 Unsigned char (uchar or uint8, bitpix=8) % DT_UINT8, NIFTI_TYPE_UINT8 + % 4 Signed short (int16, bitpix=16) % DT_INT16, NIFTI_TYPE_INT16 + % 8 Signed integer (int32, bitpix=32) % DT_INT32, NIFTI_TYPE_INT32 + % 16 Floating point (single or float32, bitpix=32) % DT_FLOAT32, NIFTI_TYPE_FLOAT32 + % 32 Complex, 2 float32 (Use float32, bitpix=64) % DT_COMPLEX64, NIFTI_TYPE_COMPLEX64 + % 64 Double precision (double or float64, bitpix=64) % DT_FLOAT64, NIFTI_TYPE_FLOAT64 + % 128 uint8 RGB (Use uint8, bitpix=24) % DT_RGB24, NIFTI_TYPE_RGB24 + % 256 Signed char (schar or int8, bitpix=8) % DT_INT8, NIFTI_TYPE_INT8 + % 511 Single RGB (Use float32, bitpix=96) % DT_RGB96, NIFTI_TYPE_RGB96 + % 512 Unsigned short (uint16, bitpix=16) % DT_UNINT16, NIFTI_TYPE_UNINT16 + % 768 Unsigned integer (uint32, bitpix=32) % DT_UNINT32, NIFTI_TYPE_UNINT32 + % 1024 Signed long long (int64, bitpix=64) % DT_INT64, NIFTI_TYPE_INT64 + % 1280 Unsigned long long (uint64, bitpix=64) % DT_UINT64, NIFTI_TYPE_UINT64 + % 1536 Long double, float128 (Unsupported, bitpix=128) % DT_FLOAT128, NIFTI_TYPE_FLOAT128 + % 1792 Complex128, 2 float64 (Use float64, bitpix=128) % DT_COMPLEX128, NIFTI_TYPE_COMPLEX128 + % 2048 Complex256, 2 float128 (Unsupported, bitpix=256) % DT_COMPLEX128, NIFTI_TYPE_COMPLEX128 + % + switch hdr.dime.datatype + case 1, + hdr.dime.bitpix = 1; precision = 'ubit1'; + case 2, + hdr.dime.bitpix = 8; precision = 'uint8'; + case 4, + hdr.dime.bitpix = 16; precision = 'int16'; + case 8, + hdr.dime.bitpix = 32; precision = 'int32'; + case 16, + hdr.dime.bitpix = 32; precision = 'float32'; + case 32, + hdr.dime.bitpix = 64; precision = 'float32'; + case 64, + hdr.dime.bitpix = 64; precision = 'float64'; + case 128, + hdr.dime.bitpix = 24; precision = 'uint8'; + case 256 + hdr.dime.bitpix = 8; precision = 'int8'; + case 511 + hdr.dime.bitpix = 96; precision = 'float32'; + case 512 + hdr.dime.bitpix = 16; precision = 'uint16'; + case 768 + hdr.dime.bitpix = 32; precision = 'uint32'; + case 1024 + hdr.dime.bitpix = 64; precision = 'int64'; + case 1280 + hdr.dime.bitpix = 64; precision = 'uint64'; + case 1792, + hdr.dime.bitpix = 128; precision = 'float64'; + otherwise + error('This datatype is not supported'); + end + + hdr.dime.dim(find(hdr.dime.dim < 1)) = 1; + + % move pointer to the start of image block + % + switch filetype + case {0, 1} + fseek(fid, 0, 'bof'); + case 2 + fseek(fid, hdr.dime.vox_offset, 'bof'); + end + + % Load whole image block for old Analyze format or binary image; + % otherwise, load images that are specified in img_idx, dim5_idx, + % dim6_idx, and dim7_idx + % + % For binary image, we have to read all because pos can not be + % seeked in bit and can not be calculated the way below. + % + if hdr.dime.datatype == 1 | isequal(hdr.dime.dim(5:8),ones(1,4)) | ... + (isempty(img_idx) & isempty(dim5_idx) & isempty(dim6_idx) & isempty(dim7_idx)) + + % For each frame, precision of value will be read + % in img_siz times, where img_siz is only the + % dimension size of an image, not the byte storage + % size of an image. + % + img_siz = prod(hdr.dime.dim(2:8)); + + % For complex float32 or complex float64, voxel values + % include [real, imag] + % + if hdr.dime.datatype == 32 | hdr.dime.datatype == 1792 + img_siz = img_siz * 2; + end + + %MPH: For RGB24, voxel values include 3 separate color planes + % + if hdr.dime.datatype == 128 | hdr.dime.datatype == 511 + img_siz = img_siz * 3; + end + + img = fread(fid, img_siz, sprintf('*%s',precision)); + + d1 = hdr.dime.dim(2); + d2 = hdr.dime.dim(3); + d3 = hdr.dime.dim(4); + d4 = hdr.dime.dim(5); + d5 = hdr.dime.dim(6); + d6 = hdr.dime.dim(7); + d7 = hdr.dime.dim(8); + + if isempty(img_idx) + img_idx = 1:d4; + end + + if isempty(dim5_idx) + dim5_idx = 1:d5; + end + + if isempty(dim6_idx) + dim6_idx = 1:d6; + end + + if isempty(dim7_idx) + dim7_idx = 1:d7; + end + else + + d1 = hdr.dime.dim(2); + d2 = hdr.dime.dim(3); + d3 = hdr.dime.dim(4); + d4 = hdr.dime.dim(5); + d5 = hdr.dime.dim(6); + d6 = hdr.dime.dim(7); + d7 = hdr.dime.dim(8); + + if isempty(img_idx) + img_idx = 1:d4; + end + + if isempty(dim5_idx) + dim5_idx = 1:d5; + end + + if isempty(dim6_idx) + dim6_idx = 1:d6; + end + + if isempty(dim7_idx) + dim7_idx = 1:d7; + end + + % compute size of one image + % + img_siz = prod(hdr.dime.dim(2:4)); + + % For complex float32 or complex float64, voxel values + % include [real, imag] + % + if hdr.dime.datatype == 32 | hdr.dime.datatype == 1792 + img_siz = img_siz * 2; + end + + %MPH: For RGB24, voxel values include 3 separate color planes + % + if hdr.dime.datatype == 128 | hdr.dime.datatype == 511 + img_siz = img_siz * 3; + end + + % preallocate img + img = zeros(img_siz, length(img_idx)*length(dim5_idx)*length(dim6_idx)*length(dim7_idx) ); + currentIndex = 1; + + for i7=1:length(dim7_idx) + for i6=1:length(dim6_idx) + for i5=1:length(dim5_idx) + for t=1:length(img_idx) + + % Position is seeked in bytes. To convert dimension size + % to byte storage size, hdr.dime.bitpix/8 will be + % applied. + % + pos = sub2ind([d1 d2 d3 d4 d5 d6 d7], 1, 1, 1, ... + img_idx(t), dim5_idx(i5),dim6_idx(i6),dim7_idx(i7)) -1; + pos = pos * hdr.dime.bitpix/8; + + if filetype == 2 + fseek(fid, pos + hdr.dime.vox_offset, 'bof'); + else + fseek(fid, pos, 'bof'); + end + + % For each frame, fread will read precision of value + % in img_siz times + % + img(:,currentIndex) = fread(fid, img_siz, sprintf('*%s',precision)); + currentIndex = currentIndex +1; + + end + end + end + end + end + + % For complex float32 or complex float64, voxel values + % include [real, imag] + % + if hdr.dime.datatype == 32 | hdr.dime.datatype == 1792 + img = reshape(img, [2, length(img)/2]); + img = complex(img(1,:)', img(2,:)'); + end + + fclose(fid); + + % Update the global min and max values + % + hdr.dime.glmax = double(max(img(:))); + hdr.dime.glmin = double(min(img(:))); + + % old_RGB treat RGB slice by slice, now it is treated voxel by voxel + % + if old_RGB & hdr.dime.datatype == 128 & hdr.dime.bitpix == 24 + % remove squeeze + img = (reshape(img, [hdr.dime.dim(2:3) 3 hdr.dime.dim(4) length(img_idx) length(dim5_idx) length(dim6_idx) length(dim7_idx)])); + img = permute(img, [1 2 4 3 5 6 7 8]); + elseif hdr.dime.datatype == 128 & hdr.dime.bitpix == 24 + % remove squeeze + img = (reshape(img, [3 hdr.dime.dim(2:4) length(img_idx) length(dim5_idx) length(dim6_idx) length(dim7_idx)])); + img = permute(img, [2 3 4 1 5 6 7 8]); + elseif hdr.dime.datatype == 511 & hdr.dime.bitpix == 96 + img = double(img(:)); + img = single((img - min(img))/(max(img) - min(img))); + % remove squeeze + img = (reshape(img, [3 hdr.dime.dim(2:4) length(img_idx) length(dim5_idx) length(dim6_idx) length(dim7_idx)])); + img = permute(img, [2 3 4 1 5 6 7 8]); + else + % remove squeeze + img = (reshape(img, [hdr.dime.dim(2:4) length(img_idx) length(dim5_idx) length(dim6_idx) length(dim7_idx)])); + end + + if ~isempty(img_idx) + hdr.dime.dim(5) = length(img_idx); + end + + if ~isempty(dim5_idx) + hdr.dime.dim(6) = length(dim5_idx); + end + + if ~isempty(dim6_idx) + hdr.dime.dim(7) = length(dim6_idx); + end + + if ~isempty(dim7_idx) + hdr.dime.dim(8) = length(dim7_idx); + end + + return % read_image + diff --git a/matlab/load_untouch0_nii_hdr.m b/matlab/load_untouch0_nii_hdr.m index 20335cb..297afaa 100644 --- a/matlab/load_untouch0_nii_hdr.m +++ b/matlab/load_untouch0_nii_hdr.m @@ -1,200 +1,200 @@ -% internal function - -% - Jimmy Shen (jimmy@rotman-baycrest.on.ca) - -function hdr = load_nii_hdr(fileprefix, machine) - - fn = sprintf('%s.hdr',fileprefix); - fid = fopen(fn,'r',machine); - - if fid < 0, - msg = sprintf('Cannot open file %s.',fn); - error(msg); - else - fseek(fid,0,'bof'); - hdr = read_header(fid); - fclose(fid); - end - - return % load_nii_hdr - - -%--------------------------------------------------------------------- -function [ dsr ] = read_header(fid) - - % Original header structures - % struct dsr - % { - % struct header_key hk; /* 0 + 40 */ - % struct image_dimension dime; /* 40 + 108 */ - % struct data_history hist; /* 148 + 200 */ - % }; /* total= 348 bytes*/ - - dsr.hk = header_key(fid); - dsr.dime = image_dimension(fid); - dsr.hist = data_history(fid); - - return % read_header - - -%--------------------------------------------------------------------- -function [ hk ] = header_key(fid) - - fseek(fid,0,'bof'); - - % Original header structures - % struct header_key /* header key */ - % { /* off + size */ - % int sizeof_hdr /* 0 + 4 */ - % char data_type[10]; /* 4 + 10 */ - % char db_name[18]; /* 14 + 18 */ - % int extents; /* 32 + 4 */ - % short int session_error; /* 36 + 2 */ - % char regular; /* 38 + 1 */ - % char hkey_un0; /* 39 + 1 */ - % }; /* total=40 bytes */ - % - % int sizeof_header Should be 348. - % char regular Must be 'r' to indicate that all images and - % volumes are the same size. - - v6 = version; - if str2num(v6(1))<6 - directchar = '*char'; - else - directchar = 'uchar=>char'; - end - - hk.sizeof_hdr = fread(fid, 1,'int32')'; % should be 348! - hk.data_type = deblank(fread(fid,10,directchar)'); - hk.db_name = deblank(fread(fid,18,directchar)'); - hk.extents = fread(fid, 1,'int32')'; - hk.session_error = fread(fid, 1,'int16')'; - hk.regular = fread(fid, 1,directchar)'; - hk.hkey_un0 = fread(fid, 1,directchar)'; - - return % header_key - - -%--------------------------------------------------------------------- -function [ dime ] = image_dimension(fid) - - %struct image_dimension - % { /* off + size */ - % short int dim[8]; /* 0 + 16 */ - % /* - % dim[0] Number of dimensions in database; usually 4. - % dim[1] Image X dimension; number of *pixels* in an image row. - % dim[2] Image Y dimension; number of *pixel rows* in slice. - % dim[3] Volume Z dimension; number of *slices* in a volume. - % dim[4] Time points; number of volumes in database - % */ - % char vox_units[4]; /* 16 + 4 */ - % char cal_units[8]; /* 20 + 8 */ - % short int unused1; /* 28 + 2 */ - % short int datatype; /* 30 + 2 */ - % short int bitpix; /* 32 + 2 */ - % short int dim_un0; /* 34 + 2 */ - % float pixdim[8]; /* 36 + 32 */ - % /* - % pixdim[] specifies the voxel dimensions: - % pixdim[1] - voxel width, mm - % pixdim[2] - voxel height, mm - % pixdim[3] - slice thickness, mm - % pixdim[4] - volume timing, in msec - % ..etc - % */ - % float vox_offset; /* 68 + 4 */ - % float roi_scale; /* 72 + 4 */ - % float funused1; /* 76 + 4 */ - % float funused2; /* 80 + 4 */ - % float cal_max; /* 84 + 4 */ - % float cal_min; /* 88 + 4 */ - % int compressed; /* 92 + 4 */ - % int verified; /* 96 + 4 */ - % int glmax; /* 100 + 4 */ - % int glmin; /* 104 + 4 */ - % }; /* total=108 bytes */ - - v6 = version; - if str2num(v6(1))<6 - directchar = '*char'; - else - directchar = 'uchar=>char'; - end - - dime.dim = fread(fid,8,'int16')'; - dime.vox_units = deblank(fread(fid,4,directchar)'); - dime.cal_units = deblank(fread(fid,8,directchar)'); - dime.unused1 = fread(fid,1,'int16')'; - dime.datatype = fread(fid,1,'int16')'; - dime.bitpix = fread(fid,1,'int16')'; - dime.dim_un0 = fread(fid,1,'int16')'; - dime.pixdim = fread(fid,8,'float32')'; - dime.vox_offset = fread(fid,1,'float32')'; - dime.roi_scale = fread(fid,1,'float32')'; - dime.funused1 = fread(fid,1,'float32')'; - dime.funused2 = fread(fid,1,'float32')'; - dime.cal_max = fread(fid,1,'float32')'; - dime.cal_min = fread(fid,1,'float32')'; - dime.compressed = fread(fid,1,'int32')'; - dime.verified = fread(fid,1,'int32')'; - dime.glmax = fread(fid,1,'int32')'; - dime.glmin = fread(fid,1,'int32')'; - - return % image_dimension - - -%--------------------------------------------------------------------- -function [ hist ] = data_history(fid) - - %struct data_history - % { /* off + size */ - % char descrip[80]; /* 0 + 80 */ - % char aux_file[24]; /* 80 + 24 */ - % char orient; /* 104 + 1 */ - % char originator[10]; /* 105 + 10 */ - % char generated[10]; /* 115 + 10 */ - % char scannum[10]; /* 125 + 10 */ - % char patient_id[10]; /* 135 + 10 */ - % char exp_date[10]; /* 145 + 10 */ - % char exp_time[10]; /* 155 + 10 */ - % char hist_un0[3]; /* 165 + 3 */ - % int views /* 168 + 4 */ - % int vols_added; /* 172 + 4 */ - % int start_field; /* 176 + 4 */ - % int field_skip; /* 180 + 4 */ - % int omax; /* 184 + 4 */ - % int omin; /* 188 + 4 */ - % int smax; /* 192 + 4 */ - % int smin; /* 196 + 4 */ - % }; /* total=200 bytes */ - - v6 = version; - if str2num(v6(1))<6 - directchar = '*char'; - else - directchar = 'uchar=>char'; - end - - hist.descrip = deblank(fread(fid,80,directchar)'); - hist.aux_file = deblank(fread(fid,24,directchar)'); - hist.orient = fread(fid, 1,'char')'; - hist.originator = fread(fid, 5,'int16')'; - hist.generated = deblank(fread(fid,10,directchar)'); - hist.scannum = deblank(fread(fid,10,directchar)'); - hist.patient_id = deblank(fread(fid,10,directchar)'); - hist.exp_date = deblank(fread(fid,10,directchar)'); - hist.exp_time = deblank(fread(fid,10,directchar)'); - hist.hist_un0 = deblank(fread(fid, 3,directchar)'); - hist.views = fread(fid, 1,'int32')'; - hist.vols_added = fread(fid, 1,'int32')'; - hist.start_field = fread(fid, 1,'int32')'; - hist.field_skip = fread(fid, 1,'int32')'; - hist.omax = fread(fid, 1,'int32')'; - hist.omin = fread(fid, 1,'int32')'; - hist.smax = fread(fid, 1,'int32')'; - hist.smin = fread(fid, 1,'int32')'; - - return % data_history - +% internal function + +% - Jimmy Shen (jimmy@rotman-baycrest.on.ca) + +function hdr = load_nii_hdr(fileprefix, machine) + + fn = sprintf('%s.hdr',fileprefix); + fid = fopen(fn,'r',machine); + + if fid < 0, + msg = sprintf('Cannot open file %s.',fn); + error(msg); + else + fseek(fid,0,'bof'); + hdr = read_header(fid); + fclose(fid); + end + + return % load_nii_hdr + + +%--------------------------------------------------------------------- +function [ dsr ] = read_header(fid) + + % Original header structures + % struct dsr + % { + % struct header_key hk; /* 0 + 40 */ + % struct image_dimension dime; /* 40 + 108 */ + % struct data_history hist; /* 148 + 200 */ + % }; /* total= 348 bytes*/ + + dsr.hk = header_key(fid); + dsr.dime = image_dimension(fid); + dsr.hist = data_history(fid); + + return % read_header + + +%--------------------------------------------------------------------- +function [ hk ] = header_key(fid) + + fseek(fid,0,'bof'); + + % Original header structures + % struct header_key /* header key */ + % { /* off + size */ + % int sizeof_hdr /* 0 + 4 */ + % char data_type[10]; /* 4 + 10 */ + % char db_name[18]; /* 14 + 18 */ + % int extents; /* 32 + 4 */ + % short int session_error; /* 36 + 2 */ + % char regular; /* 38 + 1 */ + % char hkey_un0; /* 39 + 1 */ + % }; /* total=40 bytes */ + % + % int sizeof_header Should be 348. + % char regular Must be 'r' to indicate that all images and + % volumes are the same size. + + v6 = version; + if str2num(v6(1))<6 + directchar = '*char'; + else + directchar = 'uchar=>char'; + end + + hk.sizeof_hdr = fread(fid, 1,'int32')'; % should be 348! + hk.data_type = deblank(fread(fid,10,directchar)'); + hk.db_name = deblank(fread(fid,18,directchar)'); + hk.extents = fread(fid, 1,'int32')'; + hk.session_error = fread(fid, 1,'int16')'; + hk.regular = fread(fid, 1,directchar)'; + hk.hkey_un0 = fread(fid, 1,directchar)'; + + return % header_key + + +%--------------------------------------------------------------------- +function [ dime ] = image_dimension(fid) + + %struct image_dimension + % { /* off + size */ + % short int dim[8]; /* 0 + 16 */ + % /* + % dim[0] Number of dimensions in database; usually 4. + % dim[1] Image X dimension; number of *pixels* in an image row. + % dim[2] Image Y dimension; number of *pixel rows* in slice. + % dim[3] Volume Z dimension; number of *slices* in a volume. + % dim[4] Time points; number of volumes in database + % */ + % char vox_units[4]; /* 16 + 4 */ + % char cal_units[8]; /* 20 + 8 */ + % short int unused1; /* 28 + 2 */ + % short int datatype; /* 30 + 2 */ + % short int bitpix; /* 32 + 2 */ + % short int dim_un0; /* 34 + 2 */ + % float pixdim[8]; /* 36 + 32 */ + % /* + % pixdim[] specifies the voxel dimensions: + % pixdim[1] - voxel width, mm + % pixdim[2] - voxel height, mm + % pixdim[3] - slice thickness, mm + % pixdim[4] - volume timing, in msec + % ..etc + % */ + % float vox_offset; /* 68 + 4 */ + % float roi_scale; /* 72 + 4 */ + % float funused1; /* 76 + 4 */ + % float funused2; /* 80 + 4 */ + % float cal_max; /* 84 + 4 */ + % float cal_min; /* 88 + 4 */ + % int compressed; /* 92 + 4 */ + % int verified; /* 96 + 4 */ + % int glmax; /* 100 + 4 */ + % int glmin; /* 104 + 4 */ + % }; /* total=108 bytes */ + + v6 = version; + if str2num(v6(1))<6 + directchar = '*char'; + else + directchar = 'uchar=>char'; + end + + dime.dim = fread(fid,8,'int16')'; + dime.vox_units = deblank(fread(fid,4,directchar)'); + dime.cal_units = deblank(fread(fid,8,directchar)'); + dime.unused1 = fread(fid,1,'int16')'; + dime.datatype = fread(fid,1,'int16')'; + dime.bitpix = fread(fid,1,'int16')'; + dime.dim_un0 = fread(fid,1,'int16')'; + dime.pixdim = fread(fid,8,'float32')'; + dime.vox_offset = fread(fid,1,'float32')'; + dime.roi_scale = fread(fid,1,'float32')'; + dime.funused1 = fread(fid,1,'float32')'; + dime.funused2 = fread(fid,1,'float32')'; + dime.cal_max = fread(fid,1,'float32')'; + dime.cal_min = fread(fid,1,'float32')'; + dime.compressed = fread(fid,1,'int32')'; + dime.verified = fread(fid,1,'int32')'; + dime.glmax = fread(fid,1,'int32')'; + dime.glmin = fread(fid,1,'int32')'; + + return % image_dimension + + +%--------------------------------------------------------------------- +function [ hist ] = data_history(fid) + + %struct data_history + % { /* off + size */ + % char descrip[80]; /* 0 + 80 */ + % char aux_file[24]; /* 80 + 24 */ + % char orient; /* 104 + 1 */ + % char originator[10]; /* 105 + 10 */ + % char generated[10]; /* 115 + 10 */ + % char scannum[10]; /* 125 + 10 */ + % char patient_id[10]; /* 135 + 10 */ + % char exp_date[10]; /* 145 + 10 */ + % char exp_time[10]; /* 155 + 10 */ + % char hist_un0[3]; /* 165 + 3 */ + % int views /* 168 + 4 */ + % int vols_added; /* 172 + 4 */ + % int start_field; /* 176 + 4 */ + % int field_skip; /* 180 + 4 */ + % int omax; /* 184 + 4 */ + % int omin; /* 188 + 4 */ + % int smax; /* 192 + 4 */ + % int smin; /* 196 + 4 */ + % }; /* total=200 bytes */ + + v6 = version; + if str2num(v6(1))<6 + directchar = '*char'; + else + directchar = 'uchar=>char'; + end + + hist.descrip = deblank(fread(fid,80,directchar)'); + hist.aux_file = deblank(fread(fid,24,directchar)'); + hist.orient = fread(fid, 1,'char')'; + hist.originator = fread(fid, 5,'int16')'; + hist.generated = deblank(fread(fid,10,directchar)'); + hist.scannum = deblank(fread(fid,10,directchar)'); + hist.patient_id = deblank(fread(fid,10,directchar)'); + hist.exp_date = deblank(fread(fid,10,directchar)'); + hist.exp_time = deblank(fread(fid,10,directchar)'); + hist.hist_un0 = deblank(fread(fid, 3,directchar)'); + hist.views = fread(fid, 1,'int32')'; + hist.vols_added = fread(fid, 1,'int32')'; + hist.start_field = fread(fid, 1,'int32')'; + hist.field_skip = fread(fid, 1,'int32')'; + hist.omax = fread(fid, 1,'int32')'; + hist.omin = fread(fid, 1,'int32')'; + hist.smax = fread(fid, 1,'int32')'; + hist.smin = fread(fid, 1,'int32')'; + + return % data_history + diff --git a/matlab/load_untouch_nii.m b/matlab/load_untouch_nii.m index f12e989..1a07c08 100644 --- a/matlab/load_untouch_nii.m +++ b/matlab/load_untouch_nii.m @@ -1,128 +1,128 @@ -% Load NIFTI or ANALYZE dataset, but not applying any appropriate affine -% geometric transform or voxel intensity scaling. -% -% Although according to NIFTI website, all those header information are -% supposed to be applied to the loaded NIFTI image, there are some -% situations that people do want to leave the original NIFTI header and -% data untouched. They will probably just use MATLAB to do certain image -% processing regardless of image orientation, and to save data back with -% the same NIfTI header. -% -% Since this program is only served for those situations, please use it -% together with "save_untouch_nii.m", and do not use "save_nii.m" or -% "view_nii.m" for the data that is loaded by "load_untouch_nii.m". For -% normal situation, you should use "load_nii.m" instead. -% -% Usage: nii = load_untouch_nii(filename, [img_idx], [dim5_idx], [dim6_idx], ... -% [dim7_idx], [old_RGB], [slice_idx]) -% -% filename - NIFTI or ANALYZE file name. -% -% img_idx (optional) - a numerical array of image volume indices. -% Only the specified volumes will be loaded. All available image -% volumes will be loaded, if it is default or empty. -% -% The number of images scans can be obtained from get_nii_frame.m, -% or simply: hdr.dime.dim(5). -% -% dim5_idx (optional) - a numerical array of 5th dimension indices. -% Only the specified range will be loaded. All available range -% will be loaded, if it is default or empty. -% -% dim6_idx (optional) - a numerical array of 6th dimension indices. -% Only the specified range will be loaded. All available range -% will be loaded, if it is default or empty. -% -% dim7_idx (optional) - a numerical array of 7th dimension indices. -% Only the specified range will be loaded. All available range -% will be loaded, if it is default or empty. -% -% old_RGB (optional) - a scale number to tell difference of new RGB24 -% from old RGB24. New RGB24 uses RGB triple sequentially for each -% voxel, like [R1 G1 B1 R2 G2 B2 ...]. Analyze 6.0 from AnalyzeDirect -% uses old RGB24, in a way like [R1 R2 ... G1 G2 ... B1 B2 ...] for -% each slices. If the image that you view is garbled, try to set -% old_RGB variable to 1 and try again, because it could be in -% old RGB24. It will be set to 0, if it is default or empty. -% -% slice_idx (optional) - a numerical array of image slice indices. -% Only the specified volumes will be loaded. All available image -% slices will be loaded, if it is default or empty. -% -% Returned values: -% -% nii structure: -% -% hdr - struct with NIFTI header fields. -% -% filetype - Analyze format .hdr/.img (0); -% NIFTI .hdr/.img (1); -% NIFTI .nii (2) -% -% fileprefix - NIFTI filename without extension. -% -% machine - machine string variable. -% -% img - 3D (or 4D) matrix of NIFTI data. -% -% - Jimmy Shen (jimmy@rotman-baycrest.on.ca) -% -function nii = load_untouch_nii(filename, img_idx, dim5_idx, dim6_idx, dim7_idx, ... - old_RGB, slice_idx) - - if ~exist('filename','var') - error('Usage: nii = load_untouch_nii(filename, [img_idx], [dim5_idx], [dim6_idx], [dim7_idx], [old_RGB], [slice_idx])'); - end - - if ~exist('img_idx','var') | isempty(img_idx) - img_idx = []; - end - - if ~exist('dim5_idx','var') | isempty(dim5_idx) - dim5_idx = []; - end - - if ~exist('dim6_idx','var') | isempty(dim6_idx) - dim6_idx = []; - end - - if ~exist('dim7_idx','var') | isempty(dim7_idx) - dim7_idx = []; - end - - if ~exist('old_RGB','var') | isempty(old_RGB) - old_RGB = 0; - end - - if ~exist('slice_idx','var') | isempty(slice_idx) - slice_idx = []; - end - - % Read the dataset header - % - [nii.hdr,nii.filetype,nii.fileprefix,nii.machine] = load_nii_hdr(filename); - - if nii.filetype == 0 - nii.hdr = load_untouch0_nii_hdr(nii.fileprefix,nii.machine); - nii.ext = []; - else - nii.hdr = load_untouch_nii_hdr(nii.fileprefix,nii.machine,nii.filetype); - - % Read the header extension - % - nii.ext = load_nii_ext(filename); - end - - % Read the dataset body - % - [nii.img,nii.hdr] = load_untouch_nii_img(nii.hdr,nii.filetype,nii.fileprefix, ... - nii.machine,img_idx,dim5_idx,dim6_idx,dim7_idx,old_RGB,slice_idx); - - % Perform some of sform/qform transform - % -% nii = xform_nii(nii, tolerance, preferredForm); - - nii.untouch = 1; - - return % load_untouch_nii - +% Load NIFTI or ANALYZE dataset, but not applying any appropriate affine +% geometric transform or voxel intensity scaling. +% +% Although according to NIFTI website, all those header information are +% supposed to be applied to the loaded NIFTI image, there are some +% situations that people do want to leave the original NIFTI header and +% data untouched. They will probably just use MATLAB to do certain image +% processing regardless of image orientation, and to save data back with +% the same NIfTI header. +% +% Since this program is only served for those situations, please use it +% together with "save_untouch_nii.m", and do not use "save_nii.m" or +% "view_nii.m" for the data that is loaded by "load_untouch_nii.m". For +% normal situation, you should use "load_nii.m" instead. +% +% Usage: nii = load_untouch_nii(filename, [img_idx], [dim5_idx], [dim6_idx], ... +% [dim7_idx], [old_RGB], [slice_idx]) +% +% filename - NIFTI or ANALYZE file name. +% +% img_idx (optional) - a numerical array of image volume indices. +% Only the specified volumes will be loaded. All available image +% volumes will be loaded, if it is default or empty. +% +% The number of images scans can be obtained from get_nii_frame.m, +% or simply: hdr.dime.dim(5). +% +% dim5_idx (optional) - a numerical array of 5th dimension indices. +% Only the specified range will be loaded. All available range +% will be loaded, if it is default or empty. +% +% dim6_idx (optional) - a numerical array of 6th dimension indices. +% Only the specified range will be loaded. All available range +% will be loaded, if it is default or empty. +% +% dim7_idx (optional) - a numerical array of 7th dimension indices. +% Only the specified range will be loaded. All available range +% will be loaded, if it is default or empty. +% +% old_RGB (optional) - a scale number to tell difference of new RGB24 +% from old RGB24. New RGB24 uses RGB triple sequentially for each +% voxel, like [R1 G1 B1 R2 G2 B2 ...]. Analyze 6.0 from AnalyzeDirect +% uses old RGB24, in a way like [R1 R2 ... G1 G2 ... B1 B2 ...] for +% each slices. If the image that you view is garbled, try to set +% old_RGB variable to 1 and try again, because it could be in +% old RGB24. It will be set to 0, if it is default or empty. +% +% slice_idx (optional) - a numerical array of image slice indices. +% Only the specified volumes will be loaded. All available image +% slices will be loaded, if it is default or empty. +% +% Returned values: +% +% nii structure: +% +% hdr - struct with NIFTI header fields. +% +% filetype - Analyze format .hdr/.img (0); +% NIFTI .hdr/.img (1); +% NIFTI .nii (2) +% +% fileprefix - NIFTI filename without extension. +% +% machine - machine string variable. +% +% img - 3D (or 4D) matrix of NIFTI data. +% +% - Jimmy Shen (jimmy@rotman-baycrest.on.ca) +% +function nii = load_untouch_nii(filename, img_idx, dim5_idx, dim6_idx, dim7_idx, ... + old_RGB, slice_idx) + + if ~exist('filename','var') + error('Usage: nii = load_untouch_nii(filename, [img_idx], [dim5_idx], [dim6_idx], [dim7_idx], [old_RGB], [slice_idx])'); + end + + if ~exist('img_idx','var') | isempty(img_idx) + img_idx = []; + end + + if ~exist('dim5_idx','var') | isempty(dim5_idx) + dim5_idx = []; + end + + if ~exist('dim6_idx','var') | isempty(dim6_idx) + dim6_idx = []; + end + + if ~exist('dim7_idx','var') | isempty(dim7_idx) + dim7_idx = []; + end + + if ~exist('old_RGB','var') | isempty(old_RGB) + old_RGB = 0; + end + + if ~exist('slice_idx','var') | isempty(slice_idx) + slice_idx = []; + end + + % Read the dataset header + % + [nii.hdr,nii.filetype,nii.fileprefix,nii.machine] = load_nii_hdr(filename); + + if nii.filetype == 0 + nii.hdr = load_untouch0_nii_hdr(nii.fileprefix,nii.machine); + nii.ext = []; + else + nii.hdr = load_untouch_nii_hdr(nii.fileprefix,nii.machine,nii.filetype); + + % Read the header extension + % + nii.ext = load_nii_ext(filename); + end + + % Read the dataset body + % + [nii.img,nii.hdr] = load_untouch_nii_img(nii.hdr,nii.filetype,nii.fileprefix, ... + nii.machine,img_idx,dim5_idx,dim6_idx,dim7_idx,old_RGB,slice_idx); + + % Perform some of sform/qform transform + % +% nii = xform_nii(nii, tolerance, preferredForm); + + nii.untouch = 1; + + return % load_untouch_nii + diff --git a/matlab/load_untouch_nii_hdr.m b/matlab/load_untouch_nii_hdr.m index ee91caf..a471536 100644 --- a/matlab/load_untouch_nii_hdr.m +++ b/matlab/load_untouch_nii_hdr.m @@ -1,217 +1,217 @@ -% internal function - -% - Jimmy Shen (jimmy@rotman-baycrest.on.ca) - -function hdr = load_nii_hdr(fileprefix, machine, filetype) - - if filetype == 2 - fn = sprintf('%s.nii',fileprefix); - - if ~exist(fn) - msg = sprintf('Cannot find file "%s.nii".', fileprefix); - error(msg); - end - else - fn = sprintf('%s.hdr',fileprefix); - - if ~exist(fn) - msg = sprintf('Cannot find file "%s.hdr".', fileprefix); - error(msg); - end - end - - fid = fopen(fn,'r',machine); - - if fid < 0, - msg = sprintf('Cannot open file %s.',fn); - error(msg); - else - fseek(fid,0,'bof'); - hdr = read_header(fid); - fclose(fid); - end - - return % load_nii_hdr - - -%--------------------------------------------------------------------- -function [ dsr ] = read_header(fid) - - % Original header structures - % struct dsr - % { - % struct header_key hk; /* 0 + 40 */ - % struct image_dimension dime; /* 40 + 108 */ - % struct data_history hist; /* 148 + 200 */ - % }; /* total= 348 bytes*/ - - dsr.hk = header_key(fid); - dsr.dime = image_dimension(fid); - dsr.hist = data_history(fid); - - % For Analyze data format - % - if ~strcmp(dsr.hist.magic, 'n+1') & ~strcmp(dsr.hist.magic, 'ni1') - dsr.hist.qform_code = 0; - dsr.hist.sform_code = 0; - end - - return % read_header - - -%--------------------------------------------------------------------- -function [ hk ] = header_key(fid) - - fseek(fid,0,'bof'); - - % Original header structures - % struct header_key /* header key */ - % { /* off + size */ - % int sizeof_hdr /* 0 + 4 */ - % char data_type[10]; /* 4 + 10 */ - % char db_name[18]; /* 14 + 18 */ - % int extents; /* 32 + 4 */ - % short int session_error; /* 36 + 2 */ - % char regular; /* 38 + 1 */ - % char dim_info; % char hkey_un0; /* 39 + 1 */ - % }; /* total=40 bytes */ - % - % int sizeof_header Should be 348. - % char regular Must be 'r' to indicate that all images and - % volumes are the same size. - - v6 = version; - if str2num(v6(1))<6 - directchar = '*char'; - else - directchar = 'uchar=>char'; - end - - hk.sizeof_hdr = fread(fid, 1,'int32')'; % should be 348! - hk.data_type = deblank(fread(fid,10,directchar)'); - hk.db_name = deblank(fread(fid,18,directchar)'); - hk.extents = fread(fid, 1,'int32')'; - hk.session_error = fread(fid, 1,'int16')'; - hk.regular = fread(fid, 1,directchar)'; - hk.dim_info = fread(fid, 1,'uchar')'; - - return % header_key - - -%--------------------------------------------------------------------- -function [ dime ] = image_dimension(fid) - - % Original header structures - % struct image_dimension - % { /* off + size */ - % short int dim[8]; /* 0 + 16 */ - % /* - % dim[0] Number of dimensions in database; usually 4. - % dim[1] Image X dimension; number of *pixels* in an image row. - % dim[2] Image Y dimension; number of *pixel rows* in slice. - % dim[3] Volume Z dimension; number of *slices* in a volume. - % dim[4] Time points; number of volumes in database - % */ - % float intent_p1; % char vox_units[4]; /* 16 + 4 */ - % float intent_p2; % char cal_units[8]; /* 20 + 4 */ - % float intent_p3; % char cal_units[8]; /* 24 + 4 */ - % short int intent_code; % short int unused1; /* 28 + 2 */ - % short int datatype; /* 30 + 2 */ - % short int bitpix; /* 32 + 2 */ - % short int slice_start; % short int dim_un0; /* 34 + 2 */ - % float pixdim[8]; /* 36 + 32 */ - % /* - % pixdim[] specifies the voxel dimensions: - % pixdim[1] - voxel width, mm - % pixdim[2] - voxel height, mm - % pixdim[3] - slice thickness, mm - % pixdim[4] - volume timing, in msec - % ..etc - % */ - % float vox_offset; /* 68 + 4 */ - % float scl_slope; % float roi_scale; /* 72 + 4 */ - % float scl_inter; % float funused1; /* 76 + 4 */ - % short slice_end; % float funused2; /* 80 + 2 */ - % char slice_code; % float funused2; /* 82 + 1 */ - % char xyzt_units; % float funused2; /* 83 + 1 */ - % float cal_max; /* 84 + 4 */ - % float cal_min; /* 88 + 4 */ - % float slice_duration; % int compressed; /* 92 + 4 */ - % float toffset; % int verified; /* 96 + 4 */ - % int glmax; /* 100 + 4 */ - % int glmin; /* 104 + 4 */ - % }; /* total=108 bytes */ - - dime.dim = fread(fid,8,'int16')'; - dime.intent_p1 = fread(fid,1,'float32')'; - dime.intent_p2 = fread(fid,1,'float32')'; - dime.intent_p3 = fread(fid,1,'float32')'; - dime.intent_code = fread(fid,1,'int16')'; - dime.datatype = fread(fid,1,'int16')'; - dime.bitpix = fread(fid,1,'int16')'; - dime.slice_start = fread(fid,1,'int16')'; - dime.pixdim = fread(fid,8,'float32')'; - dime.vox_offset = fread(fid,1,'float32')'; - dime.scl_slope = fread(fid,1,'float32')'; - dime.scl_inter = fread(fid,1,'float32')'; - dime.slice_end = fread(fid,1,'int16')'; - dime.slice_code = fread(fid,1,'uchar')'; - dime.xyzt_units = fread(fid,1,'uchar')'; - dime.cal_max = fread(fid,1,'float32')'; - dime.cal_min = fread(fid,1,'float32')'; - dime.slice_duration = fread(fid,1,'float32')'; - dime.toffset = fread(fid,1,'float32')'; - dime.glmax = fread(fid,1,'int32')'; - dime.glmin = fread(fid,1,'int32')'; - - return % image_dimension - - -%--------------------------------------------------------------------- -function [ hist ] = data_history(fid) - - % Original header structures - % struct data_history - % { /* off + size */ - % char descrip[80]; /* 0 + 80 */ - % char aux_file[24]; /* 80 + 24 */ - % short int qform_code; /* 104 + 2 */ - % short int sform_code; /* 106 + 2 */ - % float quatern_b; /* 108 + 4 */ - % float quatern_c; /* 112 + 4 */ - % float quatern_d; /* 116 + 4 */ - % float qoffset_x; /* 120 + 4 */ - % float qoffset_y; /* 124 + 4 */ - % float qoffset_z; /* 128 + 4 */ - % float srow_x[4]; /* 132 + 16 */ - % float srow_y[4]; /* 148 + 16 */ - % float srow_z[4]; /* 164 + 16 */ - % char intent_name[16]; /* 180 + 16 */ - % char magic[4]; % int smin; /* 196 + 4 */ - % }; /* total=200 bytes */ - - v6 = version; - if str2num(v6(1))<6 - directchar = '*char'; - else - directchar = 'uchar=>char'; - end - - hist.descrip = deblank(fread(fid,80,directchar)'); - hist.aux_file = deblank(fread(fid,24,directchar)'); - hist.qform_code = fread(fid,1,'int16')'; - hist.sform_code = fread(fid,1,'int16')'; - hist.quatern_b = fread(fid,1,'float32')'; - hist.quatern_c = fread(fid,1,'float32')'; - hist.quatern_d = fread(fid,1,'float32')'; - hist.qoffset_x = fread(fid,1,'float32')'; - hist.qoffset_y = fread(fid,1,'float32')'; - hist.qoffset_z = fread(fid,1,'float32')'; - hist.srow_x = fread(fid,4,'float32')'; - hist.srow_y = fread(fid,4,'float32')'; - hist.srow_z = fread(fid,4,'float32')'; - hist.intent_name = deblank(fread(fid,16,directchar)'); - hist.magic = deblank(fread(fid,4,directchar)'); - - return % data_history - +% internal function + +% - Jimmy Shen (jimmy@rotman-baycrest.on.ca) + +function hdr = load_nii_hdr(fileprefix, machine, filetype) + + if filetype == 2 + fn = sprintf('%s.nii',fileprefix); + + if ~exist(fn) + msg = sprintf('Cannot find file "%s.nii".', fileprefix); + error(msg); + end + else + fn = sprintf('%s.hdr',fileprefix); + + if ~exist(fn) + msg = sprintf('Cannot find file "%s.hdr".', fileprefix); + error(msg); + end + end + + fid = fopen(fn,'r',machine); + + if fid < 0, + msg = sprintf('Cannot open file %s.',fn); + error(msg); + else + fseek(fid,0,'bof'); + hdr = read_header(fid); + fclose(fid); + end + + return % load_nii_hdr + + +%--------------------------------------------------------------------- +function [ dsr ] = read_header(fid) + + % Original header structures + % struct dsr + % { + % struct header_key hk; /* 0 + 40 */ + % struct image_dimension dime; /* 40 + 108 */ + % struct data_history hist; /* 148 + 200 */ + % }; /* total= 348 bytes*/ + + dsr.hk = header_key(fid); + dsr.dime = image_dimension(fid); + dsr.hist = data_history(fid); + + % For Analyze data format + % + if ~strcmp(dsr.hist.magic, 'n+1') & ~strcmp(dsr.hist.magic, 'ni1') + dsr.hist.qform_code = 0; + dsr.hist.sform_code = 0; + end + + return % read_header + + +%--------------------------------------------------------------------- +function [ hk ] = header_key(fid) + + fseek(fid,0,'bof'); + + % Original header structures + % struct header_key /* header key */ + % { /* off + size */ + % int sizeof_hdr /* 0 + 4 */ + % char data_type[10]; /* 4 + 10 */ + % char db_name[18]; /* 14 + 18 */ + % int extents; /* 32 + 4 */ + % short int session_error; /* 36 + 2 */ + % char regular; /* 38 + 1 */ + % char dim_info; % char hkey_un0; /* 39 + 1 */ + % }; /* total=40 bytes */ + % + % int sizeof_header Should be 348. + % char regular Must be 'r' to indicate that all images and + % volumes are the same size. + + v6 = version; + if str2num(v6(1))<6 + directchar = '*char'; + else + directchar = 'uchar=>char'; + end + + hk.sizeof_hdr = fread(fid, 1,'int32')'; % should be 348! + hk.data_type = deblank(fread(fid,10,directchar)'); + hk.db_name = deblank(fread(fid,18,directchar)'); + hk.extents = fread(fid, 1,'int32')'; + hk.session_error = fread(fid, 1,'int16')'; + hk.regular = fread(fid, 1,directchar)'; + hk.dim_info = fread(fid, 1,'uchar')'; + + return % header_key + + +%--------------------------------------------------------------------- +function [ dime ] = image_dimension(fid) + + % Original header structures + % struct image_dimension + % { /* off + size */ + % short int dim[8]; /* 0 + 16 */ + % /* + % dim[0] Number of dimensions in database; usually 4. + % dim[1] Image X dimension; number of *pixels* in an image row. + % dim[2] Image Y dimension; number of *pixel rows* in slice. + % dim[3] Volume Z dimension; number of *slices* in a volume. + % dim[4] Time points; number of volumes in database + % */ + % float intent_p1; % char vox_units[4]; /* 16 + 4 */ + % float intent_p2; % char cal_units[8]; /* 20 + 4 */ + % float intent_p3; % char cal_units[8]; /* 24 + 4 */ + % short int intent_code; % short int unused1; /* 28 + 2 */ + % short int datatype; /* 30 + 2 */ + % short int bitpix; /* 32 + 2 */ + % short int slice_start; % short int dim_un0; /* 34 + 2 */ + % float pixdim[8]; /* 36 + 32 */ + % /* + % pixdim[] specifies the voxel dimensions: + % pixdim[1] - voxel width, mm + % pixdim[2] - voxel height, mm + % pixdim[3] - slice thickness, mm + % pixdim[4] - volume timing, in msec + % ..etc + % */ + % float vox_offset; /* 68 + 4 */ + % float scl_slope; % float roi_scale; /* 72 + 4 */ + % float scl_inter; % float funused1; /* 76 + 4 */ + % short slice_end; % float funused2; /* 80 + 2 */ + % char slice_code; % float funused2; /* 82 + 1 */ + % char xyzt_units; % float funused2; /* 83 + 1 */ + % float cal_max; /* 84 + 4 */ + % float cal_min; /* 88 + 4 */ + % float slice_duration; % int compressed; /* 92 + 4 */ + % float toffset; % int verified; /* 96 + 4 */ + % int glmax; /* 100 + 4 */ + % int glmin; /* 104 + 4 */ + % }; /* total=108 bytes */ + + dime.dim = fread(fid,8,'int16')'; + dime.intent_p1 = fread(fid,1,'float32')'; + dime.intent_p2 = fread(fid,1,'float32')'; + dime.intent_p3 = fread(fid,1,'float32')'; + dime.intent_code = fread(fid,1,'int16')'; + dime.datatype = fread(fid,1,'int16')'; + dime.bitpix = fread(fid,1,'int16')'; + dime.slice_start = fread(fid,1,'int16')'; + dime.pixdim = fread(fid,8,'float32')'; + dime.vox_offset = fread(fid,1,'float32')'; + dime.scl_slope = fread(fid,1,'float32')'; + dime.scl_inter = fread(fid,1,'float32')'; + dime.slice_end = fread(fid,1,'int16')'; + dime.slice_code = fread(fid,1,'uchar')'; + dime.xyzt_units = fread(fid,1,'uchar')'; + dime.cal_max = fread(fid,1,'float32')'; + dime.cal_min = fread(fid,1,'float32')'; + dime.slice_duration = fread(fid,1,'float32')'; + dime.toffset = fread(fid,1,'float32')'; + dime.glmax = fread(fid,1,'int32')'; + dime.glmin = fread(fid,1,'int32')'; + + return % image_dimension + + +%--------------------------------------------------------------------- +function [ hist ] = data_history(fid) + + % Original header structures + % struct data_history + % { /* off + size */ + % char descrip[80]; /* 0 + 80 */ + % char aux_file[24]; /* 80 + 24 */ + % short int qform_code; /* 104 + 2 */ + % short int sform_code; /* 106 + 2 */ + % float quatern_b; /* 108 + 4 */ + % float quatern_c; /* 112 + 4 */ + % float quatern_d; /* 116 + 4 */ + % float qoffset_x; /* 120 + 4 */ + % float qoffset_y; /* 124 + 4 */ + % float qoffset_z; /* 128 + 4 */ + % float srow_x[4]; /* 132 + 16 */ + % float srow_y[4]; /* 148 + 16 */ + % float srow_z[4]; /* 164 + 16 */ + % char intent_name[16]; /* 180 + 16 */ + % char magic[4]; % int smin; /* 196 + 4 */ + % }; /* total=200 bytes */ + + v6 = version; + if str2num(v6(1))<6 + directchar = '*char'; + else + directchar = 'uchar=>char'; + end + + hist.descrip = deblank(fread(fid,80,directchar)'); + hist.aux_file = deblank(fread(fid,24,directchar)'); + hist.qform_code = fread(fid,1,'int16')'; + hist.sform_code = fread(fid,1,'int16')'; + hist.quatern_b = fread(fid,1,'float32')'; + hist.quatern_c = fread(fid,1,'float32')'; + hist.quatern_d = fread(fid,1,'float32')'; + hist.qoffset_x = fread(fid,1,'float32')'; + hist.qoffset_y = fread(fid,1,'float32')'; + hist.qoffset_z = fread(fid,1,'float32')'; + hist.srow_x = fread(fid,4,'float32')'; + hist.srow_y = fread(fid,4,'float32')'; + hist.srow_z = fread(fid,4,'float32')'; + hist.intent_name = deblank(fread(fid,16,directchar)'); + hist.magic = deblank(fread(fid,4,directchar)'); + + return % data_history + diff --git a/matlab/load_untouch_nii_img.m b/matlab/load_untouch_nii_img.m index def7339..96e9fd5 100644 --- a/matlab/load_untouch_nii_img.m +++ b/matlab/load_untouch_nii_img.m @@ -1,485 +1,485 @@ -% internal function - -% - Jimmy Shen (jimmy@rotman-baycrest.on.ca) - -function [img,hdr] = load_untouch_nii_img(hdr,filetype,fileprefix,machine,img_idx,dim5_idx,dim6_idx,dim7_idx,old_RGB,slice_idx) - - if ~exist('hdr','var') | ~exist('filetype','var') | ~exist('fileprefix','var') | ~exist('machine','var') - error('Usage: [img,hdr] = load_nii_img(hdr,filetype,fileprefix,machine,[img_idx],[dim5_idx],[dim6_idx],[dim7_idx],[old_RGB],[slice_idx]);'); - end - - if ~exist('img_idx','var') | isempty(img_idx) | hdr.dime.dim(5)<1 - img_idx = []; - end - - if ~exist('dim5_idx','var') | isempty(dim5_idx) | hdr.dime.dim(6)<1 - dim5_idx = []; - end - - if ~exist('dim6_idx','var') | isempty(dim6_idx) | hdr.dime.dim(7)<1 - dim6_idx = []; - end - - if ~exist('dim7_idx','var') | isempty(dim7_idx) | hdr.dime.dim(8)<1 - dim7_idx = []; - end - - if ~exist('old_RGB','var') | isempty(old_RGB) - old_RGB = 0; - end - - if ~exist('slice_idx','var') | isempty(slice_idx) | hdr.dime.dim(4)<1 - slice_idx = []; - end - - % check img_idx - % - if ~isempty(img_idx) & ~isnumeric(img_idx) - error('"img_idx" should be a numerical array.'); - end - - if length(unique(img_idx)) ~= length(img_idx) - error('Duplicate image index in "img_idx"'); - end - - if ~isempty(img_idx) & (min(img_idx) < 1 | max(img_idx) > hdr.dime.dim(5)) - max_range = hdr.dime.dim(5); - - if max_range == 1 - error(['"img_idx" should be 1.']); - else - range = ['1 ' num2str(max_range)]; - error(['"img_idx" should be an integer within the range of [' range '].']); - end - end - - % check dim5_idx - % - if ~isempty(dim5_idx) & ~isnumeric(dim5_idx) - error('"dim5_idx" should be a numerical array.'); - end - - if length(unique(dim5_idx)) ~= length(dim5_idx) - error('Duplicate index in "dim5_idx"'); - end - - if ~isempty(dim5_idx) & (min(dim5_idx) < 1 | max(dim5_idx) > hdr.dime.dim(6)) - max_range = hdr.dime.dim(6); - - if max_range == 1 - error(['"dim5_idx" should be 1.']); - else - range = ['1 ' num2str(max_range)]; - error(['"dim5_idx" should be an integer within the range of [' range '].']); - end - end - - % check dim6_idx - % - if ~isempty(dim6_idx) & ~isnumeric(dim6_idx) - error('"dim6_idx" should be a numerical array.'); - end - - if length(unique(dim6_idx)) ~= length(dim6_idx) - error('Duplicate index in "dim6_idx"'); - end - - if ~isempty(dim6_idx) & (min(dim6_idx) < 1 | max(dim6_idx) > hdr.dime.dim(7)) - max_range = hdr.dime.dim(7); - - if max_range == 1 - error(['"dim6_idx" should be 1.']); - else - range = ['1 ' num2str(max_range)]; - error(['"dim6_idx" should be an integer within the range of [' range '].']); - end - end - - % check dim7_idx - % - if ~isempty(dim7_idx) & ~isnumeric(dim7_idx) - error('"dim7_idx" should be a numerical array.'); - end - - if length(unique(dim7_idx)) ~= length(dim7_idx) - error('Duplicate index in "dim7_idx"'); - end - - if ~isempty(dim7_idx) & (min(dim7_idx) < 1 | max(dim7_idx) > hdr.dime.dim(8)) - max_range = hdr.dime.dim(8); - - if max_range == 1 - error(['"dim7_idx" should be 1.']); - else - range = ['1 ' num2str(max_range)]; - error(['"dim7_idx" should be an integer within the range of [' range '].']); - end - end - - % check slice_idx - % - if ~isempty(slice_idx) & ~isnumeric(slice_idx) - error('"slice_idx" should be a numerical array.'); - end - - if length(unique(slice_idx)) ~= length(slice_idx) - error('Duplicate index in "slice_idx"'); - end - - if ~isempty(slice_idx) & (min(slice_idx) < 1 | max(slice_idx) > hdr.dime.dim(4)) - max_range = hdr.dime.dim(4); - - if max_range == 1 - error(['"slice_idx" should be 1.']); - else - range = ['1 ' num2str(max_range)]; - error(['"slice_idx" should be an integer within the range of [' range '].']); - end - end - - [img,hdr] = read_image(hdr,filetype,fileprefix,machine,img_idx,dim5_idx,dim6_idx,dim7_idx,old_RGB,slice_idx); - - return % load_nii_img - - -%--------------------------------------------------------------------- -function [img,hdr] = read_image(hdr,filetype,fileprefix,machine,img_idx,dim5_idx,dim6_idx,dim7_idx,old_RGB,slice_idx) - - switch filetype - case {0, 1} - fn = [fileprefix '.img']; - case 2 - fn = [fileprefix '.nii']; - end - - fid = fopen(fn,'r',machine); - - if fid < 0, - msg = sprintf('Cannot open file %s.',fn); - error(msg); - end - - % Set bitpix according to datatype - % - % /*Acceptable values for datatype are*/ - % - % 0 None (Unknown bit per voxel) % DT_NONE, DT_UNKNOWN - % 1 Binary (ubit1, bitpix=1) % DT_BINARY - % 2 Unsigned char (uchar or uint8, bitpix=8) % DT_UINT8, NIFTI_TYPE_UINT8 - % 4 Signed short (int16, bitpix=16) % DT_INT16, NIFTI_TYPE_INT16 - % 8 Signed integer (int32, bitpix=32) % DT_INT32, NIFTI_TYPE_INT32 - % 16 Floating point (single or float32, bitpix=32) % DT_FLOAT32, NIFTI_TYPE_FLOAT32 - % 32 Complex, 2 float32 (Use float32, bitpix=64) % DT_COMPLEX64, NIFTI_TYPE_COMPLEX64 - % 64 Double precision (double or float64, bitpix=64) % DT_FLOAT64, NIFTI_TYPE_FLOAT64 - % 128 uint8 RGB (Use uint8, bitpix=24) % DT_RGB24, NIFTI_TYPE_RGB24 - % 256 Signed char (schar or int8, bitpix=8) % DT_INT8, NIFTI_TYPE_INT8 - % 511 Single RGB (Use float32, bitpix=96) % DT_RGB96, NIFTI_TYPE_RGB96 - % 512 Unsigned short (uint16, bitpix=16) % DT_UNINT16, NIFTI_TYPE_UNINT16 - % 768 Unsigned integer (uint32, bitpix=32) % DT_UNINT32, NIFTI_TYPE_UNINT32 - % 1024 Signed long long (int64, bitpix=64) % DT_INT64, NIFTI_TYPE_INT64 - % 1280 Unsigned long long (uint64, bitpix=64) % DT_UINT64, NIFTI_TYPE_UINT64 - % 1536 Long double, float128 (Unsupported, bitpix=128) % DT_FLOAT128, NIFTI_TYPE_FLOAT128 - % 1792 Complex128, 2 float64 (Use float64, bitpix=128) % DT_COMPLEX128, NIFTI_TYPE_COMPLEX128 - % 2048 Complex256, 2 float128 (Unsupported, bitpix=256) % DT_COMPLEX128, NIFTI_TYPE_COMPLEX128 - % - switch hdr.dime.datatype - case 1, - hdr.dime.bitpix = 1; precision = 'ubit1'; - case 2, - hdr.dime.bitpix = 8; precision = 'uint8'; - case 4, - hdr.dime.bitpix = 16; precision = 'int16'; - case 8, - hdr.dime.bitpix = 32; precision = 'int32'; - case 16, - hdr.dime.bitpix = 32; precision = 'float32'; - case 32, - hdr.dime.bitpix = 64; precision = 'float32'; - case 64, - hdr.dime.bitpix = 64; precision = 'float64'; - case 128, - hdr.dime.bitpix = 24; precision = 'uint8'; - case 256 - hdr.dime.bitpix = 8; precision = 'int8'; - case 511 - hdr.dime.bitpix = 96; precision = 'float32'; - case 512 - hdr.dime.bitpix = 16; precision = 'uint16'; - case 768 - hdr.dime.bitpix = 32; precision = 'uint32'; - case 1024 - hdr.dime.bitpix = 64; precision = 'int64'; - case 1280 - hdr.dime.bitpix = 64; precision = 'uint64'; - case 1792, - hdr.dime.bitpix = 128; precision = 'float64'; - otherwise - error('This datatype is not supported'); - end - - tmp = hdr.dime.dim(2:end); - tmp(find(tmp < 1)) = 1; - hdr.dime.dim(2:end) = tmp; - - % move pointer to the start of image block - % - switch filetype - case {0, 1} - fseek(fid, 0, 'bof'); - case 2 - fseek(fid, hdr.dime.vox_offset, 'bof'); - end - - % Load whole image block for old Analyze format or binary image; - % otherwise, load images that are specified in img_idx, dim5_idx, - % dim6_idx, and dim7_idx - % - % For binary image, we have to read all because pos can not be - % seeked in bit and can not be calculated the way below. - % - if hdr.dime.datatype == 1 | isequal(hdr.dime.dim(4:8),ones(1,5)) | ... - (isempty(img_idx) & isempty(dim5_idx) & isempty(dim6_idx) & isempty(dim7_idx) & isempty(slice_idx)) - - % For each frame, precision of value will be read - % in img_siz times, where img_siz is only the - % dimension size of an image, not the byte storage - % size of an image. - % - img_siz = prod(hdr.dime.dim(2:8)); - - % For complex float32 or complex float64, voxel values - % include [real, imag] - % - if hdr.dime.datatype == 32 | hdr.dime.datatype == 1792 - img_siz = img_siz * 2; - end - - %MPH: For RGB24, voxel values include 3 separate color planes - % - if hdr.dime.datatype == 128 | hdr.dime.datatype == 511 - img_siz = img_siz * 3; - end - - img = fread(fid, img_siz, sprintf('*%s',precision)); - - d1 = hdr.dime.dim(2); - d2 = hdr.dime.dim(3); - d3 = hdr.dime.dim(4); - d4 = hdr.dime.dim(5); - d5 = hdr.dime.dim(6); - d6 = hdr.dime.dim(7); - d7 = hdr.dime.dim(8); - - if isempty(slice_idx) - slice_idx = 1:d3; - end - - if isempty(img_idx) - img_idx = 1:d4; - end - - if isempty(dim5_idx) - dim5_idx = 1:d5; - end - - if isempty(dim6_idx) - dim6_idx = 1:d6; - end - - if isempty(dim7_idx) - dim7_idx = 1:d7; - end - else - - d1 = hdr.dime.dim(2); - d2 = hdr.dime.dim(3); - d3 = hdr.dime.dim(4); - d4 = hdr.dime.dim(5); - d5 = hdr.dime.dim(6); - d6 = hdr.dime.dim(7); - d7 = hdr.dime.dim(8); - - if isempty(slice_idx) - slice_idx = 1:d3; - end - - if isempty(img_idx) - img_idx = 1:d4; - end - - if isempty(dim5_idx) - dim5_idx = 1:d5; - end - - if isempty(dim6_idx) - dim6_idx = 1:d6; - end - - if isempty(dim7_idx) - dim7_idx = 1:d7; - end - - %ROMAN: begin - roman = 1; - if(roman) - - % compute size of one slice - % - img_siz = prod(hdr.dime.dim(2:3)); - - % For complex float32 or complex float64, voxel values - % include [real, imag] - % - if hdr.dime.datatype == 32 | hdr.dime.datatype == 1792 - img_siz = img_siz * 2; - end - - %MPH: For RGB24, voxel values include 3 separate color planes - % - if hdr.dime.datatype == 128 | hdr.dime.datatype == 511 - img_siz = img_siz * 3; - end - - % preallocate img - img = zeros(img_siz, length(slice_idx)*length(img_idx)*length(dim5_idx)*length(dim6_idx)*length(dim7_idx) ); - currentIndex = 1; - else - img = []; - end; %if(roman) - % ROMAN: end - - for i7=1:length(dim7_idx) - for i6=1:length(dim6_idx) - for i5=1:length(dim5_idx) - for t=1:length(img_idx) - for s=1:length(slice_idx) - - % Position is seeked in bytes. To convert dimension size - % to byte storage size, hdr.dime.bitpix/8 will be - % applied. - % - pos = sub2ind([d1 d2 d3 d4 d5 d6 d7], 1, 1, slice_idx(s), ... - img_idx(t), dim5_idx(i5),dim6_idx(i6),dim7_idx(i7)) -1; - pos = pos * hdr.dime.bitpix/8; - - % ROMAN: begin - if(roman) - % do nothing - else - img_siz = prod(hdr.dime.dim(2:3)); - - % For complex float32 or complex float64, voxel values - % include [real, imag] - % - if hdr.dime.datatype == 32 | hdr.dime.datatype == 1792 - img_siz = img_siz * 2; - end - - %MPH: For RGB24, voxel values include 3 separate color planes - % - if hdr.dime.datatype == 128 | hdr.dime.datatype == 511 - img_siz = img_siz * 3; - end - end; % if (roman) - % ROMAN: end - - if filetype == 2 - fseek(fid, pos + hdr.dime.vox_offset, 'bof'); - else - fseek(fid, pos, 'bof'); - end - - % For each frame, fread will read precision of value - % in img_siz times - % - % ROMAN: begin - if(roman) - img(:,currentIndex) = fread(fid, img_siz, sprintf('*%s',precision)); - currentIndex = currentIndex +1; - else - img = [img fread(fid, img_siz, sprintf('*%s',precision))]; - end; %if(roman) - % ROMAN: end - - end - end - end - end - end - end - - % For complex float32 or complex float64, voxel values - % include [real, imag] - % - if hdr.dime.datatype == 32 | hdr.dime.datatype == 1792 - img = reshape(img, [2, length(img)/2]); - img = complex(img(1,:)', img(2,:)'); - end - - fclose(fid); - - % Update the global min and max values - % - hdr.dime.glmax = double(max(img(:))); - hdr.dime.glmin = double(min(img(:))); - - % ANDREW ADDING THESE LINES - if (hdr.dime.dim(1) == 3) - img_idx = 1; - dim5_idx = 1; - dim6_idx = 1; - dim7_idx = 1; - elseif (hdr.dime.dim(1) == 4) - dim5_idx = 1; - dim6_idx = 1; - dim7_idx = 1; - elseif (hdr.dime.dim(1) == 5) - dim6_idx = 1; - dim7_idx = 1; - elseif (hdr.dime.dim(1) == 6) - dim7_idx = 1; - end - - % old_RGB treat RGB slice by slice, now it is treated voxel by voxel - % - if old_RGB & hdr.dime.datatype == 128 & hdr.dime.bitpix == 24 - % remove squeeze - img = (reshape(img, [hdr.dime.dim(2:3) 3 length(slice_idx) length(img_idx) length(dim5_idx) length(dim6_idx) length(dim7_idx)])); - img = permute(img, [1 2 4 3 5 6 7 8]); - elseif hdr.dime.datatype == 128 & hdr.dime.bitpix == 24 - % remove squeeze - img = (reshape(img, [3 hdr.dime.dim(2:3) length(slice_idx) length(img_idx) length(dim5_idx) length(dim6_idx) length(dim7_idx)])); - img = permute(img, [2 3 4 1 5 6 7 8]); - elseif hdr.dime.datatype == 511 & hdr.dime.bitpix == 96 - img = double(img(:)); - img = single((img - min(img))/(max(img) - min(img))); - % remove squeeze - img = (reshape(img, [3 hdr.dime.dim(2:3) length(slice_idx) length(img_idx) length(dim5_idx) length(dim6_idx) length(dim7_idx)])); - img = permute(img, [2 3 4 1 5 6 7 8]); - else - % remove squeeze - img = (reshape(img, [hdr.dime.dim(2:3) length(slice_idx) length(img_idx) length(dim5_idx) length(dim6_idx) length(dim7_idx)])); - end - - if ~isempty(slice_idx) - hdr.dime.dim(4) = length(slice_idx); - end - - if ~isempty(img_idx) - hdr.dime.dim(5) = length(img_idx); - end - - if ~isempty(dim5_idx) - hdr.dime.dim(6) = length(dim5_idx); - end - - if ~isempty(dim6_idx) - hdr.dime.dim(7) = length(dim6_idx); - end - - if ~isempty(dim7_idx) - hdr.dime.dim(8) = length(dim7_idx); - end - - return % read_image - +% internal function + +% - Jimmy Shen (jimmy@rotman-baycrest.on.ca) + +function [img,hdr] = load_untouch_nii_img(hdr,filetype,fileprefix,machine,img_idx,dim5_idx,dim6_idx,dim7_idx,old_RGB,slice_idx) + + if ~exist('hdr','var') | ~exist('filetype','var') | ~exist('fileprefix','var') | ~exist('machine','var') + error('Usage: [img,hdr] = load_nii_img(hdr,filetype,fileprefix,machine,[img_idx],[dim5_idx],[dim6_idx],[dim7_idx],[old_RGB],[slice_idx]);'); + end + + if ~exist('img_idx','var') | isempty(img_idx) | hdr.dime.dim(5)<1 + img_idx = []; + end + + if ~exist('dim5_idx','var') | isempty(dim5_idx) | hdr.dime.dim(6)<1 + dim5_idx = []; + end + + if ~exist('dim6_idx','var') | isempty(dim6_idx) | hdr.dime.dim(7)<1 + dim6_idx = []; + end + + if ~exist('dim7_idx','var') | isempty(dim7_idx) | hdr.dime.dim(8)<1 + dim7_idx = []; + end + + if ~exist('old_RGB','var') | isempty(old_RGB) + old_RGB = 0; + end + + if ~exist('slice_idx','var') | isempty(slice_idx) | hdr.dime.dim(4)<1 + slice_idx = []; + end + + % check img_idx + % + if ~isempty(img_idx) & ~isnumeric(img_idx) + error('"img_idx" should be a numerical array.'); + end + + if length(unique(img_idx)) ~= length(img_idx) + error('Duplicate image index in "img_idx"'); + end + + if ~isempty(img_idx) & (min(img_idx) < 1 | max(img_idx) > hdr.dime.dim(5)) + max_range = hdr.dime.dim(5); + + if max_range == 1 + error(['"img_idx" should be 1.']); + else + range = ['1 ' num2str(max_range)]; + error(['"img_idx" should be an integer within the range of [' range '].']); + end + end + + % check dim5_idx + % + if ~isempty(dim5_idx) & ~isnumeric(dim5_idx) + error('"dim5_idx" should be a numerical array.'); + end + + if length(unique(dim5_idx)) ~= length(dim5_idx) + error('Duplicate index in "dim5_idx"'); + end + + if ~isempty(dim5_idx) & (min(dim5_idx) < 1 | max(dim5_idx) > hdr.dime.dim(6)) + max_range = hdr.dime.dim(6); + + if max_range == 1 + error(['"dim5_idx" should be 1.']); + else + range = ['1 ' num2str(max_range)]; + error(['"dim5_idx" should be an integer within the range of [' range '].']); + end + end + + % check dim6_idx + % + if ~isempty(dim6_idx) & ~isnumeric(dim6_idx) + error('"dim6_idx" should be a numerical array.'); + end + + if length(unique(dim6_idx)) ~= length(dim6_idx) + error('Duplicate index in "dim6_idx"'); + end + + if ~isempty(dim6_idx) & (min(dim6_idx) < 1 | max(dim6_idx) > hdr.dime.dim(7)) + max_range = hdr.dime.dim(7); + + if max_range == 1 + error(['"dim6_idx" should be 1.']); + else + range = ['1 ' num2str(max_range)]; + error(['"dim6_idx" should be an integer within the range of [' range '].']); + end + end + + % check dim7_idx + % + if ~isempty(dim7_idx) & ~isnumeric(dim7_idx) + error('"dim7_idx" should be a numerical array.'); + end + + if length(unique(dim7_idx)) ~= length(dim7_idx) + error('Duplicate index in "dim7_idx"'); + end + + if ~isempty(dim7_idx) & (min(dim7_idx) < 1 | max(dim7_idx) > hdr.dime.dim(8)) + max_range = hdr.dime.dim(8); + + if max_range == 1 + error(['"dim7_idx" should be 1.']); + else + range = ['1 ' num2str(max_range)]; + error(['"dim7_idx" should be an integer within the range of [' range '].']); + end + end + + % check slice_idx + % + if ~isempty(slice_idx) & ~isnumeric(slice_idx) + error('"slice_idx" should be a numerical array.'); + end + + if length(unique(slice_idx)) ~= length(slice_idx) + error('Duplicate index in "slice_idx"'); + end + + if ~isempty(slice_idx) & (min(slice_idx) < 1 | max(slice_idx) > hdr.dime.dim(4)) + max_range = hdr.dime.dim(4); + + if max_range == 1 + error(['"slice_idx" should be 1.']); + else + range = ['1 ' num2str(max_range)]; + error(['"slice_idx" should be an integer within the range of [' range '].']); + end + end + + [img,hdr] = read_image(hdr,filetype,fileprefix,machine,img_idx,dim5_idx,dim6_idx,dim7_idx,old_RGB,slice_idx); + + return % load_nii_img + + +%--------------------------------------------------------------------- +function [img,hdr] = read_image(hdr,filetype,fileprefix,machine,img_idx,dim5_idx,dim6_idx,dim7_idx,old_RGB,slice_idx) + + switch filetype + case {0, 1} + fn = [fileprefix '.img']; + case 2 + fn = [fileprefix '.nii']; + end + + fid = fopen(fn,'r',machine); + + if fid < 0, + msg = sprintf('Cannot open file %s.',fn); + error(msg); + end + + % Set bitpix according to datatype + % + % /*Acceptable values for datatype are*/ + % + % 0 None (Unknown bit per voxel) % DT_NONE, DT_UNKNOWN + % 1 Binary (ubit1, bitpix=1) % DT_BINARY + % 2 Unsigned char (uchar or uint8, bitpix=8) % DT_UINT8, NIFTI_TYPE_UINT8 + % 4 Signed short (int16, bitpix=16) % DT_INT16, NIFTI_TYPE_INT16 + % 8 Signed integer (int32, bitpix=32) % DT_INT32, NIFTI_TYPE_INT32 + % 16 Floating point (single or float32, bitpix=32) % DT_FLOAT32, NIFTI_TYPE_FLOAT32 + % 32 Complex, 2 float32 (Use float32, bitpix=64) % DT_COMPLEX64, NIFTI_TYPE_COMPLEX64 + % 64 Double precision (double or float64, bitpix=64) % DT_FLOAT64, NIFTI_TYPE_FLOAT64 + % 128 uint8 RGB (Use uint8, bitpix=24) % DT_RGB24, NIFTI_TYPE_RGB24 + % 256 Signed char (schar or int8, bitpix=8) % DT_INT8, NIFTI_TYPE_INT8 + % 511 Single RGB (Use float32, bitpix=96) % DT_RGB96, NIFTI_TYPE_RGB96 + % 512 Unsigned short (uint16, bitpix=16) % DT_UNINT16, NIFTI_TYPE_UNINT16 + % 768 Unsigned integer (uint32, bitpix=32) % DT_UNINT32, NIFTI_TYPE_UNINT32 + % 1024 Signed long long (int64, bitpix=64) % DT_INT64, NIFTI_TYPE_INT64 + % 1280 Unsigned long long (uint64, bitpix=64) % DT_UINT64, NIFTI_TYPE_UINT64 + % 1536 Long double, float128 (Unsupported, bitpix=128) % DT_FLOAT128, NIFTI_TYPE_FLOAT128 + % 1792 Complex128, 2 float64 (Use float64, bitpix=128) % DT_COMPLEX128, NIFTI_TYPE_COMPLEX128 + % 2048 Complex256, 2 float128 (Unsupported, bitpix=256) % DT_COMPLEX128, NIFTI_TYPE_COMPLEX128 + % + switch hdr.dime.datatype + case 1, + hdr.dime.bitpix = 1; precision = 'ubit1'; + case 2, + hdr.dime.bitpix = 8; precision = 'uint8'; + case 4, + hdr.dime.bitpix = 16; precision = 'int16'; + case 8, + hdr.dime.bitpix = 32; precision = 'int32'; + case 16, + hdr.dime.bitpix = 32; precision = 'float32'; + case 32, + hdr.dime.bitpix = 64; precision = 'float32'; + case 64, + hdr.dime.bitpix = 64; precision = 'float64'; + case 128, + hdr.dime.bitpix = 24; precision = 'uint8'; + case 256 + hdr.dime.bitpix = 8; precision = 'int8'; + case 511 + hdr.dime.bitpix = 96; precision = 'float32'; + case 512 + hdr.dime.bitpix = 16; precision = 'uint16'; + case 768 + hdr.dime.bitpix = 32; precision = 'uint32'; + case 1024 + hdr.dime.bitpix = 64; precision = 'int64'; + case 1280 + hdr.dime.bitpix = 64; precision = 'uint64'; + case 1792, + hdr.dime.bitpix = 128; precision = 'float64'; + otherwise + error('This datatype is not supported'); + end + + tmp = hdr.dime.dim(2:end); + tmp(find(tmp < 1)) = 1; + hdr.dime.dim(2:end) = tmp; + + % move pointer to the start of image block + % + switch filetype + case {0, 1} + fseek(fid, 0, 'bof'); + case 2 + fseek(fid, hdr.dime.vox_offset, 'bof'); + end + + % Load whole image block for old Analyze format or binary image; + % otherwise, load images that are specified in img_idx, dim5_idx, + % dim6_idx, and dim7_idx + % + % For binary image, we have to read all because pos can not be + % seeked in bit and can not be calculated the way below. + % + if hdr.dime.datatype == 1 | isequal(hdr.dime.dim(4:8),ones(1,5)) | ... + (isempty(img_idx) & isempty(dim5_idx) & isempty(dim6_idx) & isempty(dim7_idx) & isempty(slice_idx)) + + % For each frame, precision of value will be read + % in img_siz times, where img_siz is only the + % dimension size of an image, not the byte storage + % size of an image. + % + img_siz = prod(hdr.dime.dim(2:8)); + + % For complex float32 or complex float64, voxel values + % include [real, imag] + % + if hdr.dime.datatype == 32 | hdr.dime.datatype == 1792 + img_siz = img_siz * 2; + end + + %MPH: For RGB24, voxel values include 3 separate color planes + % + if hdr.dime.datatype == 128 | hdr.dime.datatype == 511 + img_siz = img_siz * 3; + end + + img = fread(fid, img_siz, sprintf('*%s',precision)); + + d1 = hdr.dime.dim(2); + d2 = hdr.dime.dim(3); + d3 = hdr.dime.dim(4); + d4 = hdr.dime.dim(5); + d5 = hdr.dime.dim(6); + d6 = hdr.dime.dim(7); + d7 = hdr.dime.dim(8); + + if isempty(slice_idx) + slice_idx = 1:d3; + end + + if isempty(img_idx) + img_idx = 1:d4; + end + + if isempty(dim5_idx) + dim5_idx = 1:d5; + end + + if isempty(dim6_idx) + dim6_idx = 1:d6; + end + + if isempty(dim7_idx) + dim7_idx = 1:d7; + end + else + + d1 = hdr.dime.dim(2); + d2 = hdr.dime.dim(3); + d3 = hdr.dime.dim(4); + d4 = hdr.dime.dim(5); + d5 = hdr.dime.dim(6); + d6 = hdr.dime.dim(7); + d7 = hdr.dime.dim(8); + + if isempty(slice_idx) + slice_idx = 1:d3; + end + + if isempty(img_idx) + img_idx = 1:d4; + end + + if isempty(dim5_idx) + dim5_idx = 1:d5; + end + + if isempty(dim6_idx) + dim6_idx = 1:d6; + end + + if isempty(dim7_idx) + dim7_idx = 1:d7; + end + + %ROMAN: begin + roman = 1; + if(roman) + + % compute size of one slice + % + img_siz = prod(hdr.dime.dim(2:3)); + + % For complex float32 or complex float64, voxel values + % include [real, imag] + % + if hdr.dime.datatype == 32 | hdr.dime.datatype == 1792 + img_siz = img_siz * 2; + end + + %MPH: For RGB24, voxel values include 3 separate color planes + % + if hdr.dime.datatype == 128 | hdr.dime.datatype == 511 + img_siz = img_siz * 3; + end + + % preallocate img + img = zeros(img_siz, length(slice_idx)*length(img_idx)*length(dim5_idx)*length(dim6_idx)*length(dim7_idx) ); + currentIndex = 1; + else + img = []; + end; %if(roman) + % ROMAN: end + + for i7=1:length(dim7_idx) + for i6=1:length(dim6_idx) + for i5=1:length(dim5_idx) + for t=1:length(img_idx) + for s=1:length(slice_idx) + + % Position is seeked in bytes. To convert dimension size + % to byte storage size, hdr.dime.bitpix/8 will be + % applied. + % + pos = sub2ind([d1 d2 d3 d4 d5 d6 d7], 1, 1, slice_idx(s), ... + img_idx(t), dim5_idx(i5),dim6_idx(i6),dim7_idx(i7)) -1; + pos = pos * hdr.dime.bitpix/8; + + % ROMAN: begin + if(roman) + % do nothing + else + img_siz = prod(hdr.dime.dim(2:3)); + + % For complex float32 or complex float64, voxel values + % include [real, imag] + % + if hdr.dime.datatype == 32 | hdr.dime.datatype == 1792 + img_siz = img_siz * 2; + end + + %MPH: For RGB24, voxel values include 3 separate color planes + % + if hdr.dime.datatype == 128 | hdr.dime.datatype == 511 + img_siz = img_siz * 3; + end + end; % if (roman) + % ROMAN: end + + if filetype == 2 + fseek(fid, pos + hdr.dime.vox_offset, 'bof'); + else + fseek(fid, pos, 'bof'); + end + + % For each frame, fread will read precision of value + % in img_siz times + % + % ROMAN: begin + if(roman) + img(:,currentIndex) = fread(fid, img_siz, sprintf('*%s',precision)); + currentIndex = currentIndex +1; + else + img = [img fread(fid, img_siz, sprintf('*%s',precision))]; + end; %if(roman) + % ROMAN: end + + end + end + end + end + end + end + + % For complex float32 or complex float64, voxel values + % include [real, imag] + % + if hdr.dime.datatype == 32 | hdr.dime.datatype == 1792 + img = reshape(img, [2, length(img)/2]); + img = complex(img(1,:)', img(2,:)'); + end + + fclose(fid); + + % Update the global min and max values + % + hdr.dime.glmax = double(max(img(:))); + hdr.dime.glmin = double(min(img(:))); + + % ANDREW ADDING THESE LINES + if (hdr.dime.dim(1) == 3) + img_idx = 1; + dim5_idx = 1; + dim6_idx = 1; + dim7_idx = 1; + elseif (hdr.dime.dim(1) == 4) + dim5_idx = 1; + dim6_idx = 1; + dim7_idx = 1; + elseif (hdr.dime.dim(1) == 5) + dim6_idx = 1; + dim7_idx = 1; + elseif (hdr.dime.dim(1) == 6) + dim7_idx = 1; + end + + % old_RGB treat RGB slice by slice, now it is treated voxel by voxel + % + if old_RGB & hdr.dime.datatype == 128 & hdr.dime.bitpix == 24 + % remove squeeze + img = (reshape(img, [hdr.dime.dim(2:3) 3 length(slice_idx) length(img_idx) length(dim5_idx) length(dim6_idx) length(dim7_idx)])); + img = permute(img, [1 2 4 3 5 6 7 8]); + elseif hdr.dime.datatype == 128 & hdr.dime.bitpix == 24 + % remove squeeze + img = (reshape(img, [3 hdr.dime.dim(2:3) length(slice_idx) length(img_idx) length(dim5_idx) length(dim6_idx) length(dim7_idx)])); + img = permute(img, [2 3 4 1 5 6 7 8]); + elseif hdr.dime.datatype == 511 & hdr.dime.bitpix == 96 + img = double(img(:)); + img = single((img - min(img))/(max(img) - min(img))); + % remove squeeze + img = (reshape(img, [3 hdr.dime.dim(2:3) length(slice_idx) length(img_idx) length(dim5_idx) length(dim6_idx) length(dim7_idx)])); + img = permute(img, [2 3 4 1 5 6 7 8]); + else + % remove squeeze + img = (reshape(img, [hdr.dime.dim(2:3) length(slice_idx) length(img_idx) length(dim5_idx) length(dim6_idx) length(dim7_idx)])); + end + + if ~isempty(slice_idx) + hdr.dime.dim(4) = length(slice_idx); + end + + if ~isempty(img_idx) + hdr.dime.dim(5) = length(img_idx); + end + + if ~isempty(dim5_idx) + hdr.dime.dim(6) = length(dim5_idx); + end + + if ~isempty(dim6_idx) + hdr.dime.dim(7) = length(dim6_idx); + end + + if ~isempty(dim7_idx) + hdr.dime.dim(8) = length(dim7_idx); + end + + return % read_image + diff --git a/matlab/save_nii.m b/matlab/save_nii.m index a516e60..0d37587 100644 --- a/matlab/save_nii.m +++ b/matlab/save_nii.m @@ -1,251 +1,251 @@ -% Save NIFTI dataset. Support both *.nii and *.hdr/*.img file extension. -% If file extension is not provided, *.hdr/*.img will be used as default. -% -% Usage: save_nii(nii, filename, [old_RGB]) -% -% nii.hdr - struct with NIFTI header fields (from load_nii.m or make_nii.m) -% -% nii.img - 3D (or 4D) matrix of NIFTI data. -% -% filename - NIFTI file name. -% -% old_RGB - an optional boolean variable to handle special RGB data -% sequence [R1 R2 ... G1 G2 ... B1 B2 ...] that is used only by -% AnalyzeDirect (Analyze Software). Since both NIfTI and Analyze -% file format use RGB triple [R1 G1 B1 R2 G2 B2 ...] sequentially -% for each voxel, this variable is set to FALSE by default. If you -% would like the saved image only to be opened by AnalyzeDirect -% Software, set old_RGB to TRUE (or 1). It will be set to 0, if it -% is default or empty. -% -% Tip: to change the data type, set nii.hdr.dime.datatype, -% and nii.hdr.dime.bitpix to: -% -% 0 None (Unknown bit per voxel) % DT_NONE, DT_UNKNOWN -% 1 Binary (ubit1, bitpix=1) % DT_BINARY -% 2 Unsigned char (uchar or uint8, bitpix=8) % DT_UINT8, NIFTI_TYPE_UINT8 -% 4 Signed short (int16, bitpix=16) % DT_INT16, NIFTI_TYPE_INT16 -% 8 Signed integer (int32, bitpix=32) % DT_INT32, NIFTI_TYPE_INT32 -% 16 Floating point (single or float32, bitpix=32) % DT_FLOAT32, NIFTI_TYPE_FLOAT32 -% 32 Complex, 2 float32 (Use float32, bitpix=64) % DT_COMPLEX64, NIFTI_TYPE_COMPLEX64 -% 64 Double precision (double or float64, bitpix=64) % DT_FLOAT64, NIFTI_TYPE_FLOAT64 -% 128 uint RGB (Use uint8, bitpix=24) % DT_RGB24, NIFTI_TYPE_RGB24 -% 256 Signed char (schar or int8, bitpix=8) % DT_INT8, NIFTI_TYPE_INT8 -% 511 Single RGB (Use float32, bitpix=96) % DT_RGB96, NIFTI_TYPE_RGB96 -% 512 Unsigned short (uint16, bitpix=16) % DT_UNINT16, NIFTI_TYPE_UNINT16 -% 768 Unsigned integer (uint32, bitpix=32) % DT_UNINT32, NIFTI_TYPE_UNINT32 -% 1024 Signed long long (int64, bitpix=64) % DT_INT64, NIFTI_TYPE_INT64 -% 1280 Unsigned long long (uint64, bitpix=64) % DT_UINT64, NIFTI_TYPE_UINT64 -% 1536 Long double, float128 (Unsupported, bitpix=128) % DT_FLOAT128, NIFTI_TYPE_FLOAT128 -% 1792 Complex128, 2 float64 (Use float64, bitpix=128) % DT_COMPLEX128, NIFTI_TYPE_COMPLEX128 -% 2048 Complex256, 2 float128 (Unsupported, bitpix=256) % DT_COMPLEX128, NIFTI_TYPE_COMPLEX128 -% -% Part of this file is copied and modified from: -% http://www.mathworks.com/matlabcentral/fileexchange/1878-mri-analyze-tools -% -% NIFTI data format can be found on: http://nifti.nimh.nih.gov -% -% - Jimmy Shen (jimmy@rotman-baycrest.on.ca) -% - "old_RGB" related codes in "save_nii.m" are added by Mike Harms (2006.06.28) -% -function save_nii(nii, fileprefix, old_RGB) - - if ~exist('nii','var') | isempty(nii) | ~isfield(nii,'hdr') | ... - ~isfield(nii,'img') | ~exist('fileprefix','var') | isempty(fileprefix) - - error('Usage: save_nii(nii, filename, [old_RGB])'); - end - - if isfield(nii,'untouch') & nii.untouch == 1 - error('Usage: please use ''save_untouch_nii.m'' for the untouched structure.'); - end - - if ~exist('old_RGB','var') | isempty(old_RGB) - old_RGB = 0; - end - - filetype = 1; - - % Note: fileprefix is actually the filename you want to save - % - if findstr('.nii',fileprefix) - filetype = 2; - fileprefix = strrep(fileprefix,'.nii',''); - end - - if findstr('.hdr',fileprefix) - fileprefix = strrep(fileprefix,'.hdr',''); - end - - if findstr('.img',fileprefix) - fileprefix = strrep(fileprefix,'.img',''); - end - - write_nii(nii, filetype, fileprefix, old_RGB); - - if filetype == 1 - - % So earlier versions of SPM can also open it with correct originator - % - M=[[diag(nii.hdr.dime.pixdim(2:4)) -[nii.hdr.hist.originator(1:3).*nii.hdr.dime.pixdim(2:4)]'];[0 0 0 1]]; - save([fileprefix '.mat'], 'M'); - end - - return % save_nii - - -%----------------------------------------------------------------------------------- -function write_nii(nii, filetype, fileprefix, old_RGB) - - hdr = nii.hdr; - - if isfield(nii,'ext') & ~isempty(nii.ext) - ext = nii.ext; - [ext, esize_total] = verify_nii_ext(ext); - else - ext = []; - end - - switch double(hdr.dime.datatype), - case 1, - hdr.dime.bitpix = int16(1 ); precision = 'ubit1'; - case 2, - hdr.dime.bitpix = int16(8 ); precision = 'uint8'; - case 4, - hdr.dime.bitpix = int16(16); precision = 'int16'; - case 8, - hdr.dime.bitpix = int16(32); precision = 'int32'; - case 16, - hdr.dime.bitpix = int16(32); precision = 'float32'; - case 32, - hdr.dime.bitpix = int16(64); precision = 'float32'; - case 64, - hdr.dime.bitpix = int16(64); precision = 'float64'; - case 128, - hdr.dime.bitpix = int16(24); precision = 'uint8'; - case 256 - hdr.dime.bitpix = int16(8 ); precision = 'int8'; - case 511, - hdr.dime.bitpix = int16(96); precision = 'float32'; - case 512 - hdr.dime.bitpix = int16(16); precision = 'uint16'; - case 768 - hdr.dime.bitpix = int16(32); precision = 'uint32'; - case 1024 - hdr.dime.bitpix = int16(64); precision = 'int64'; - case 1280 - hdr.dime.bitpix = int16(64); precision = 'uint64'; - case 1792, - hdr.dime.bitpix = int16(128); precision = 'float64'; - otherwise - error('This datatype is not supported'); - end - - hdr.dime.glmax = round(double(max(nii.img(:)))); - hdr.dime.glmin = round(double(min(nii.img(:)))); - - if filetype == 2 - fid = fopen(sprintf('%s.nii',fileprefix),'w'); - - if fid < 0, - msg = sprintf('Cannot open file %s.nii.',fileprefix); - error(msg); - end - - hdr.dime.vox_offset = 352; - - if ~isempty(ext) - hdr.dime.vox_offset = hdr.dime.vox_offset + esize_total; - end - - hdr.hist.magic = 'n+1'; - save_nii_hdr(hdr, fid); - - if ~isempty(ext) - save_nii_ext(ext, fid); - end - else - fid = fopen(sprintf('%s.hdr',fileprefix),'w'); - - if fid < 0, - msg = sprintf('Cannot open file %s.hdr.',fileprefix); - error(msg); - end - - hdr.dime.vox_offset = 0; - hdr.hist.magic = 'ni1'; - save_nii_hdr(hdr, fid); - - if ~isempty(ext) - save_nii_ext(ext, fid); - end - - fclose(fid); - fid = fopen(sprintf('%s.img',fileprefix),'w'); - end - - ScanDim = double(hdr.dime.dim(5)); % t - SliceDim = double(hdr.dime.dim(4)); % z - RowDim = double(hdr.dime.dim(3)); % y - PixelDim = double(hdr.dime.dim(2)); % x - SliceSz = double(hdr.dime.pixdim(4)); - RowSz = double(hdr.dime.pixdim(3)); - PixelSz = double(hdr.dime.pixdim(2)); - - x = 1:PixelDim; - - if filetype == 2 & isempty(ext) - skip_bytes = double(hdr.dime.vox_offset) - 348; - else - skip_bytes = 0; - end - - if double(hdr.dime.datatype) == 128 - - % RGB planes are expected to be in the 4th dimension of nii.img - % - if(size(nii.img,4)~=3) - error(['The NII structure does not appear to have 3 RGB color planes in the 4th dimension']); - end - - if old_RGB - nii.img = permute(nii.img, [1 2 4 3 5 6 7 8]); - else - nii.img = permute(nii.img, [4 1 2 3 5 6 7 8]); - end - end - - if double(hdr.dime.datatype) == 511 - - % RGB planes are expected to be in the 4th dimension of nii.img - % - if(size(nii.img,4)~=3) - error(['The NII structure does not appear to have 3 RGB color planes in the 4th dimension']); - end - - if old_RGB - nii.img = permute(nii.img, [1 2 4 3 5 6 7 8]); - else - nii.img = permute(nii.img, [4 1 2 3 5 6 7 8]); - end - end - - % For complex float32 or complex float64, voxel values - % include [real, imag] - % - if hdr.dime.datatype == 32 | hdr.dime.datatype == 1792 - real_img = real(nii.img(:))'; - nii.img = imag(nii.img(:))'; - nii.img = [real_img; nii.img]; - end - - if skip_bytes - fwrite(fid, zeros(1,skip_bytes), 'uint8'); - end - - fwrite(fid, nii.img, precision); -% fwrite(fid, nii.img, precision, skip_bytes); % error using skip - fclose(fid); - - return; % write_nii - +% Save NIFTI dataset. Support both *.nii and *.hdr/*.img file extension. +% If file extension is not provided, *.hdr/*.img will be used as default. +% +% Usage: save_nii(nii, filename, [old_RGB]) +% +% nii.hdr - struct with NIFTI header fields (from load_nii.m or make_nii.m) +% +% nii.img - 3D (or 4D) matrix of NIFTI data. +% +% filename - NIFTI file name. +% +% old_RGB - an optional boolean variable to handle special RGB data +% sequence [R1 R2 ... G1 G2 ... B1 B2 ...] that is used only by +% AnalyzeDirect (Analyze Software). Since both NIfTI and Analyze +% file format use RGB triple [R1 G1 B1 R2 G2 B2 ...] sequentially +% for each voxel, this variable is set to FALSE by default. If you +% would like the saved image only to be opened by AnalyzeDirect +% Software, set old_RGB to TRUE (or 1). It will be set to 0, if it +% is default or empty. +% +% Tip: to change the data type, set nii.hdr.dime.datatype, +% and nii.hdr.dime.bitpix to: +% +% 0 None (Unknown bit per voxel) % DT_NONE, DT_UNKNOWN +% 1 Binary (ubit1, bitpix=1) % DT_BINARY +% 2 Unsigned char (uchar or uint8, bitpix=8) % DT_UINT8, NIFTI_TYPE_UINT8 +% 4 Signed short (int16, bitpix=16) % DT_INT16, NIFTI_TYPE_INT16 +% 8 Signed integer (int32, bitpix=32) % DT_INT32, NIFTI_TYPE_INT32 +% 16 Floating point (single or float32, bitpix=32) % DT_FLOAT32, NIFTI_TYPE_FLOAT32 +% 32 Complex, 2 float32 (Use float32, bitpix=64) % DT_COMPLEX64, NIFTI_TYPE_COMPLEX64 +% 64 Double precision (double or float64, bitpix=64) % DT_FLOAT64, NIFTI_TYPE_FLOAT64 +% 128 uint RGB (Use uint8, bitpix=24) % DT_RGB24, NIFTI_TYPE_RGB24 +% 256 Signed char (schar or int8, bitpix=8) % DT_INT8, NIFTI_TYPE_INT8 +% 511 Single RGB (Use float32, bitpix=96) % DT_RGB96, NIFTI_TYPE_RGB96 +% 512 Unsigned short (uint16, bitpix=16) % DT_UNINT16, NIFTI_TYPE_UNINT16 +% 768 Unsigned integer (uint32, bitpix=32) % DT_UNINT32, NIFTI_TYPE_UNINT32 +% 1024 Signed long long (int64, bitpix=64) % DT_INT64, NIFTI_TYPE_INT64 +% 1280 Unsigned long long (uint64, bitpix=64) % DT_UINT64, NIFTI_TYPE_UINT64 +% 1536 Long double, float128 (Unsupported, bitpix=128) % DT_FLOAT128, NIFTI_TYPE_FLOAT128 +% 1792 Complex128, 2 float64 (Use float64, bitpix=128) % DT_COMPLEX128, NIFTI_TYPE_COMPLEX128 +% 2048 Complex256, 2 float128 (Unsupported, bitpix=256) % DT_COMPLEX128, NIFTI_TYPE_COMPLEX128 +% +% Part of this file is copied and modified from: +% http://www.mathworks.com/matlabcentral/fileexchange/1878-mri-analyze-tools +% +% NIFTI data format can be found on: http://nifti.nimh.nih.gov +% +% - Jimmy Shen (jimmy@rotman-baycrest.on.ca) +% - "old_RGB" related codes in "save_nii.m" are added by Mike Harms (2006.06.28) +% +function save_nii(nii, fileprefix, old_RGB) + + if ~exist('nii','var') | isempty(nii) | ~isfield(nii,'hdr') | ... + ~isfield(nii,'img') | ~exist('fileprefix','var') | isempty(fileprefix) + + error('Usage: save_nii(nii, filename, [old_RGB])'); + end + + if isfield(nii,'untouch') & nii.untouch == 1 + error('Usage: please use ''save_untouch_nii.m'' for the untouched structure.'); + end + + if ~exist('old_RGB','var') | isempty(old_RGB) + old_RGB = 0; + end + + filetype = 1; + + % Note: fileprefix is actually the filename you want to save + % + if findstr('.nii',fileprefix) + filetype = 2; + fileprefix = strrep(fileprefix,'.nii',''); + end + + if findstr('.hdr',fileprefix) + fileprefix = strrep(fileprefix,'.hdr',''); + end + + if findstr('.img',fileprefix) + fileprefix = strrep(fileprefix,'.img',''); + end + + write_nii(nii, filetype, fileprefix, old_RGB); + + if filetype == 1 + + % So earlier versions of SPM can also open it with correct originator + % + M=[[diag(nii.hdr.dime.pixdim(2:4)) -[nii.hdr.hist.originator(1:3).*nii.hdr.dime.pixdim(2:4)]'];[0 0 0 1]]; + save([fileprefix '.mat'], 'M'); + end + + return % save_nii + + +%----------------------------------------------------------------------------------- +function write_nii(nii, filetype, fileprefix, old_RGB) + + hdr = nii.hdr; + + if isfield(nii,'ext') & ~isempty(nii.ext) + ext = nii.ext; + [ext, esize_total] = verify_nii_ext(ext); + else + ext = []; + end + + switch double(hdr.dime.datatype), + case 1, + hdr.dime.bitpix = int16(1 ); precision = 'ubit1'; + case 2, + hdr.dime.bitpix = int16(8 ); precision = 'uint8'; + case 4, + hdr.dime.bitpix = int16(16); precision = 'int16'; + case 8, + hdr.dime.bitpix = int16(32); precision = 'int32'; + case 16, + hdr.dime.bitpix = int16(32); precision = 'float32'; + case 32, + hdr.dime.bitpix = int16(64); precision = 'float32'; + case 64, + hdr.dime.bitpix = int16(64); precision = 'float64'; + case 128, + hdr.dime.bitpix = int16(24); precision = 'uint8'; + case 256 + hdr.dime.bitpix = int16(8 ); precision = 'int8'; + case 511, + hdr.dime.bitpix = int16(96); precision = 'float32'; + case 512 + hdr.dime.bitpix = int16(16); precision = 'uint16'; + case 768 + hdr.dime.bitpix = int16(32); precision = 'uint32'; + case 1024 + hdr.dime.bitpix = int16(64); precision = 'int64'; + case 1280 + hdr.dime.bitpix = int16(64); precision = 'uint64'; + case 1792, + hdr.dime.bitpix = int16(128); precision = 'float64'; + otherwise + error('This datatype is not supported'); + end + + hdr.dime.glmax = round(double(max(nii.img(:)))); + hdr.dime.glmin = round(double(min(nii.img(:)))); + + if filetype == 2 + fid = fopen(sprintf('%s.nii',fileprefix),'w'); + + if fid < 0, + msg = sprintf('Cannot open file %s.nii.',fileprefix); + error(msg); + end + + hdr.dime.vox_offset = 352; + + if ~isempty(ext) + hdr.dime.vox_offset = hdr.dime.vox_offset + esize_total; + end + + hdr.hist.magic = 'n+1'; + save_nii_hdr(hdr, fid); + + if ~isempty(ext) + save_nii_ext(ext, fid); + end + else + fid = fopen(sprintf('%s.hdr',fileprefix),'w'); + + if fid < 0, + msg = sprintf('Cannot open file %s.hdr.',fileprefix); + error(msg); + end + + hdr.dime.vox_offset = 0; + hdr.hist.magic = 'ni1'; + save_nii_hdr(hdr, fid); + + if ~isempty(ext) + save_nii_ext(ext, fid); + end + + fclose(fid); + fid = fopen(sprintf('%s.img',fileprefix),'w'); + end + + ScanDim = double(hdr.dime.dim(5)); % t + SliceDim = double(hdr.dime.dim(4)); % z + RowDim = double(hdr.dime.dim(3)); % y + PixelDim = double(hdr.dime.dim(2)); % x + SliceSz = double(hdr.dime.pixdim(4)); + RowSz = double(hdr.dime.pixdim(3)); + PixelSz = double(hdr.dime.pixdim(2)); + + x = 1:PixelDim; + + if filetype == 2 & isempty(ext) + skip_bytes = double(hdr.dime.vox_offset) - 348; + else + skip_bytes = 0; + end + + if double(hdr.dime.datatype) == 128 + + % RGB planes are expected to be in the 4th dimension of nii.img + % + if(size(nii.img,4)~=3) + error(['The NII structure does not appear to have 3 RGB color planes in the 4th dimension']); + end + + if old_RGB + nii.img = permute(nii.img, [1 2 4 3 5 6 7 8]); + else + nii.img = permute(nii.img, [4 1 2 3 5 6 7 8]); + end + end + + if double(hdr.dime.datatype) == 511 + + % RGB planes are expected to be in the 4th dimension of nii.img + % + if(size(nii.img,4)~=3) + error(['The NII structure does not appear to have 3 RGB color planes in the 4th dimension']); + end + + if old_RGB + nii.img = permute(nii.img, [1 2 4 3 5 6 7 8]); + else + nii.img = permute(nii.img, [4 1 2 3 5 6 7 8]); + end + end + + % For complex float32 or complex float64, voxel values + % include [real, imag] + % + if hdr.dime.datatype == 32 | hdr.dime.datatype == 1792 + real_img = real(nii.img(:))'; + nii.img = imag(nii.img(:))'; + nii.img = [real_img; nii.img]; + end + + if skip_bytes + fwrite(fid, zeros(1,skip_bytes), 'uint8'); + end + + fwrite(fid, nii.img, precision); +% fwrite(fid, nii.img, precision, skip_bytes); % error using skip + fclose(fid); + + return; % write_nii + diff --git a/matlab/save_nii_ext.m b/matlab/save_nii_ext.m index 4788649..5e1509c 100644 --- a/matlab/save_nii_ext.m +++ b/matlab/save_nii_ext.m @@ -1,38 +1,38 @@ -% Save NIFTI header extension. -% -% Usage: save_nii_ext(ext, fid) -% -% ext - struct with NIFTI header extension fields. -% -% NIFTI data format can be found on: http://nifti.nimh.nih.gov -% -% - Jimmy Shen (jimmy@rotman-baycrest.on.ca) -% -function save_nii_ext(ext, fid) - - if ~exist('ext','var') | ~exist('fid','var') - error('Usage: save_nii_ext(ext, fid)'); - end - - if ~isfield(ext,'extension') | ~isfield(ext,'section') | ~isfield(ext,'num_ext') - error('Wrong header extension'); - end - - write_ext(ext, fid); - - return; % save_nii_ext - - -%--------------------------------------------------------------------- -function write_ext(ext, fid) - - fwrite(fid, ext.extension, 'uchar'); - - for i=1:ext.num_ext - fwrite(fid, ext.section(i).esize, 'int32'); - fwrite(fid, ext.section(i).ecode, 'int32'); - fwrite(fid, ext.section(i).edata, 'uchar'); - end - - return; % write_ext - +% Save NIFTI header extension. +% +% Usage: save_nii_ext(ext, fid) +% +% ext - struct with NIFTI header extension fields. +% +% NIFTI data format can be found on: http://nifti.nimh.nih.gov +% +% - Jimmy Shen (jimmy@rotman-baycrest.on.ca) +% +function save_nii_ext(ext, fid) + + if ~exist('ext','var') | ~exist('fid','var') + error('Usage: save_nii_ext(ext, fid)'); + end + + if ~isfield(ext,'extension') | ~isfield(ext,'section') | ~isfield(ext,'num_ext') + error('Wrong header extension'); + end + + write_ext(ext, fid); + + return; % save_nii_ext + + +%--------------------------------------------------------------------- +function write_ext(ext, fid) + + fwrite(fid, ext.extension, 'uchar'); + + for i=1:ext.num_ext + fwrite(fid, ext.section(i).esize, 'int32'); + fwrite(fid, ext.section(i).ecode, 'int32'); + fwrite(fid, ext.section(i).edata, 'uchar'); + end + + return; % write_ext + diff --git a/matlab/save_nii_hdr.m b/matlab/save_nii_hdr.m index d3160a2..225f297 100644 --- a/matlab/save_nii_hdr.m +++ b/matlab/save_nii_hdr.m @@ -1,227 +1,227 @@ -% internal function - -% - Jimmy Shen (jimmy@rotman-baycrest.on.ca) - -function save_nii_hdr(hdr, fid) - - if ~exist('hdr','var') | ~exist('fid','var') - error('Usage: save_nii_hdr(hdr, fid)'); - end - - if ~isequal(hdr.hk.sizeof_hdr,348), - error('hdr.hk.sizeof_hdr must be 348.'); - end - - if hdr.hist.qform_code == 0 & hdr.hist.sform_code == 0 - hdr.hist.sform_code = 1; - hdr.hist.srow_x(1) = hdr.dime.pixdim(2); - hdr.hist.srow_x(2) = 0; - hdr.hist.srow_x(3) = 0; - hdr.hist.srow_y(1) = 0; - hdr.hist.srow_y(2) = hdr.dime.pixdim(3); - hdr.hist.srow_y(3) = 0; - hdr.hist.srow_z(1) = 0; - hdr.hist.srow_z(2) = 0; - hdr.hist.srow_z(3) = hdr.dime.pixdim(4); - hdr.hist.srow_x(4) = (1-hdr.hist.originator(1))*hdr.dime.pixdim(2); - hdr.hist.srow_y(4) = (1-hdr.hist.originator(2))*hdr.dime.pixdim(3); - hdr.hist.srow_z(4) = (1-hdr.hist.originator(3))*hdr.dime.pixdim(4); - end - - write_header(hdr, fid); - - return; % save_nii_hdr - - -%--------------------------------------------------------------------- -function write_header(hdr, fid) - - % Original header structures - % struct dsr /* dsr = hdr */ - % { - % struct header_key hk; /* 0 + 40 */ - % struct image_dimension dime; /* 40 + 108 */ - % struct data_history hist; /* 148 + 200 */ - % }; /* total= 348 bytes*/ - - header_key(fid, hdr.hk); - image_dimension(fid, hdr.dime); - data_history(fid, hdr.hist); - - % check the file size is 348 bytes - % - fbytes = ftell(fid); - - if ~isequal(fbytes,348), - msg = sprintf('Header size is not 348 bytes.'); - warning(msg); - end - - return; % write_header - - -%--------------------------------------------------------------------- -function header_key(fid, hk) - - fseek(fid,0,'bof'); - - % Original header structures - % struct header_key /* header key */ - % { /* off + size */ - % int sizeof_hdr /* 0 + 4 */ - % char data_type[10]; /* 4 + 10 */ - % char db_name[18]; /* 14 + 18 */ - % int extents; /* 32 + 4 */ - % short int session_error; /* 36 + 2 */ - % char regular; /* 38 + 1 */ - % char dim_info; % char hkey_un0; /* 39 + 1 */ - % }; /* total=40 bytes */ - - fwrite(fid, hk.sizeof_hdr(1), 'int32'); % must be 348. - - % data_type = sprintf('%-10s',hk.data_type); % ensure it is 10 chars from left - % fwrite(fid, data_type(1:10), 'uchar'); - pad = zeros(1, 10-length(hk.data_type)); - hk.data_type = [hk.data_type char(pad)]; - fwrite(fid, hk.data_type(1:10), 'uchar'); - - % db_name = sprintf('%-18s', hk.db_name); % ensure it is 18 chars from left - % fwrite(fid, db_name(1:18), 'uchar'); - pad = zeros(1, 18-length(hk.db_name)); - hk.db_name = [hk.db_name char(pad)]; - fwrite(fid, hk.db_name(1:18), 'uchar'); - - fwrite(fid, hk.extents(1), 'int32'); - fwrite(fid, hk.session_error(1), 'int16'); - fwrite(fid, hk.regular(1), 'uchar'); % might be uint8 - - % fwrite(fid, hk.hkey_un0(1), 'uchar'); - % fwrite(fid, hk.hkey_un0(1), 'uint8'); - fwrite(fid, hk.dim_info(1), 'uchar'); - - return; % header_key - - -%--------------------------------------------------------------------- -function image_dimension(fid, dime) - - % Original header structures - % struct image_dimension - % { /* off + size */ - % short int dim[8]; /* 0 + 16 */ - % float intent_p1; % char vox_units[4]; /* 16 + 4 */ - % float intent_p2; % char cal_units[8]; /* 20 + 4 */ - % float intent_p3; % char cal_units[8]; /* 24 + 4 */ - % short int intent_code; % short int unused1; /* 28 + 2 */ - % short int datatype; /* 30 + 2 */ - % short int bitpix; /* 32 + 2 */ - % short int slice_start; % short int dim_un0; /* 34 + 2 */ - % float pixdim[8]; /* 36 + 32 */ - % /* - % pixdim[] specifies the voxel dimensions: - % pixdim[1] - voxel width - % pixdim[2] - voxel height - % pixdim[3] - interslice distance - % pixdim[4] - volume timing, in msec - % ..etc - % */ - % float vox_offset; /* 68 + 4 */ - % float scl_slope; % float roi_scale; /* 72 + 4 */ - % float scl_inter; % float funused1; /* 76 + 4 */ - % short slice_end; % float funused2; /* 80 + 2 */ - % char slice_code; % float funused2; /* 82 + 1 */ - % char xyzt_units; % float funused2; /* 83 + 1 */ - % float cal_max; /* 84 + 4 */ - % float cal_min; /* 88 + 4 */ - % float slice_duration; % int compressed; /* 92 + 4 */ - % float toffset; % int verified; /* 96 + 4 */ - % int glmax; /* 100 + 4 */ - % int glmin; /* 104 + 4 */ - % }; /* total=108 bytes */ - - fwrite(fid, dime.dim(1:8), 'int16'); - fwrite(fid, dime.intent_p1(1), 'float32'); - fwrite(fid, dime.intent_p2(1), 'float32'); - fwrite(fid, dime.intent_p3(1), 'float32'); - fwrite(fid, dime.intent_code(1), 'int16'); - fwrite(fid, dime.datatype(1), 'int16'); - fwrite(fid, dime.bitpix(1), 'int16'); - fwrite(fid, dime.slice_start(1), 'int16'); - fwrite(fid, dime.pixdim(1:8), 'float32'); - fwrite(fid, dime.vox_offset(1), 'float32'); - fwrite(fid, dime.scl_slope(1), 'float32'); - fwrite(fid, dime.scl_inter(1), 'float32'); - fwrite(fid, dime.slice_end(1), 'int16'); - fwrite(fid, dime.slice_code(1), 'uchar'); - fwrite(fid, dime.xyzt_units(1), 'uchar'); - fwrite(fid, dime.cal_max(1), 'float32'); - fwrite(fid, dime.cal_min(1), 'float32'); - fwrite(fid, dime.slice_duration(1), 'float32'); - fwrite(fid, dime.toffset(1), 'float32'); - fwrite(fid, dime.glmax(1), 'int32'); - fwrite(fid, dime.glmin(1), 'int32'); - - return; % image_dimension - - -%--------------------------------------------------------------------- -function data_history(fid, hist) - - % Original header structures - %struct data_history - % { /* off + size */ - % char descrip[80]; /* 0 + 80 */ - % char aux_file[24]; /* 80 + 24 */ - % short int qform_code; /* 104 + 2 */ - % short int sform_code; /* 106 + 2 */ - % float quatern_b; /* 108 + 4 */ - % float quatern_c; /* 112 + 4 */ - % float quatern_d; /* 116 + 4 */ - % float qoffset_x; /* 120 + 4 */ - % float qoffset_y; /* 124 + 4 */ - % float qoffset_z; /* 128 + 4 */ - % float srow_x[4]; /* 132 + 16 */ - % float srow_y[4]; /* 148 + 16 */ - % float srow_z[4]; /* 164 + 16 */ - % char intent_name[16]; /* 180 + 16 */ - % char magic[4]; % int smin; /* 196 + 4 */ - % }; /* total=200 bytes */ - - % descrip = sprintf('%-80s', hist.descrip); % 80 chars from left - % fwrite(fid, descrip(1:80), 'uchar'); - pad = zeros(1, 80-length(hist.descrip)); - hist.descrip = [hist.descrip char(pad)]; - fwrite(fid, hist.descrip(1:80), 'uchar'); - - % aux_file = sprintf('%-24s', hist.aux_file); % 24 chars from left - % fwrite(fid, aux_file(1:24), 'uchar'); - pad = zeros(1, 24-length(hist.aux_file)); - hist.aux_file = [hist.aux_file char(pad)]; - fwrite(fid, hist.aux_file(1:24), 'uchar'); - - fwrite(fid, hist.qform_code, 'int16'); - fwrite(fid, hist.sform_code, 'int16'); - fwrite(fid, hist.quatern_b, 'float32'); - fwrite(fid, hist.quatern_c, 'float32'); - fwrite(fid, hist.quatern_d, 'float32'); - fwrite(fid, hist.qoffset_x, 'float32'); - fwrite(fid, hist.qoffset_y, 'float32'); - fwrite(fid, hist.qoffset_z, 'float32'); - fwrite(fid, hist.srow_x(1:4), 'float32'); - fwrite(fid, hist.srow_y(1:4), 'float32'); - fwrite(fid, hist.srow_z(1:4), 'float32'); - - % intent_name = sprintf('%-16s', hist.intent_name); % 16 chars from left - % fwrite(fid, intent_name(1:16), 'uchar'); - pad = zeros(1, 16-length(hist.intent_name)); - hist.intent_name = [hist.intent_name char(pad)]; - fwrite(fid, hist.intent_name(1:16), 'uchar'); - - % magic = sprintf('%-4s', hist.magic); % 4 chars from left - % fwrite(fid, magic(1:4), 'uchar'); - pad = zeros(1, 4-length(hist.magic)); - hist.magic = [hist.magic char(pad)]; - fwrite(fid, hist.magic(1:4), 'uchar'); - - return; % data_history - +% internal function + +% - Jimmy Shen (jimmy@rotman-baycrest.on.ca) + +function save_nii_hdr(hdr, fid) + + if ~exist('hdr','var') | ~exist('fid','var') + error('Usage: save_nii_hdr(hdr, fid)'); + end + + if ~isequal(hdr.hk.sizeof_hdr,348), + error('hdr.hk.sizeof_hdr must be 348.'); + end + + if hdr.hist.qform_code == 0 & hdr.hist.sform_code == 0 + hdr.hist.sform_code = 1; + hdr.hist.srow_x(1) = hdr.dime.pixdim(2); + hdr.hist.srow_x(2) = 0; + hdr.hist.srow_x(3) = 0; + hdr.hist.srow_y(1) = 0; + hdr.hist.srow_y(2) = hdr.dime.pixdim(3); + hdr.hist.srow_y(3) = 0; + hdr.hist.srow_z(1) = 0; + hdr.hist.srow_z(2) = 0; + hdr.hist.srow_z(3) = hdr.dime.pixdim(4); + hdr.hist.srow_x(4) = (1-hdr.hist.originator(1))*hdr.dime.pixdim(2); + hdr.hist.srow_y(4) = (1-hdr.hist.originator(2))*hdr.dime.pixdim(3); + hdr.hist.srow_z(4) = (1-hdr.hist.originator(3))*hdr.dime.pixdim(4); + end + + write_header(hdr, fid); + + return; % save_nii_hdr + + +%--------------------------------------------------------------------- +function write_header(hdr, fid) + + % Original header structures + % struct dsr /* dsr = hdr */ + % { + % struct header_key hk; /* 0 + 40 */ + % struct image_dimension dime; /* 40 + 108 */ + % struct data_history hist; /* 148 + 200 */ + % }; /* total= 348 bytes*/ + + header_key(fid, hdr.hk); + image_dimension(fid, hdr.dime); + data_history(fid, hdr.hist); + + % check the file size is 348 bytes + % + fbytes = ftell(fid); + + if ~isequal(fbytes,348), + msg = sprintf('Header size is not 348 bytes.'); + warning(msg); + end + + return; % write_header + + +%--------------------------------------------------------------------- +function header_key(fid, hk) + + fseek(fid,0,'bof'); + + % Original header structures + % struct header_key /* header key */ + % { /* off + size */ + % int sizeof_hdr /* 0 + 4 */ + % char data_type[10]; /* 4 + 10 */ + % char db_name[18]; /* 14 + 18 */ + % int extents; /* 32 + 4 */ + % short int session_error; /* 36 + 2 */ + % char regular; /* 38 + 1 */ + % char dim_info; % char hkey_un0; /* 39 + 1 */ + % }; /* total=40 bytes */ + + fwrite(fid, hk.sizeof_hdr(1), 'int32'); % must be 348. + + % data_type = sprintf('%-10s',hk.data_type); % ensure it is 10 chars from left + % fwrite(fid, data_type(1:10), 'uchar'); + pad = zeros(1, 10-length(hk.data_type)); + hk.data_type = [hk.data_type char(pad)]; + fwrite(fid, hk.data_type(1:10), 'uchar'); + + % db_name = sprintf('%-18s', hk.db_name); % ensure it is 18 chars from left + % fwrite(fid, db_name(1:18), 'uchar'); + pad = zeros(1, 18-length(hk.db_name)); + hk.db_name = [hk.db_name char(pad)]; + fwrite(fid, hk.db_name(1:18), 'uchar'); + + fwrite(fid, hk.extents(1), 'int32'); + fwrite(fid, hk.session_error(1), 'int16'); + fwrite(fid, hk.regular(1), 'uchar'); % might be uint8 + + % fwrite(fid, hk.hkey_un0(1), 'uchar'); + % fwrite(fid, hk.hkey_un0(1), 'uint8'); + fwrite(fid, hk.dim_info(1), 'uchar'); + + return; % header_key + + +%--------------------------------------------------------------------- +function image_dimension(fid, dime) + + % Original header structures + % struct image_dimension + % { /* off + size */ + % short int dim[8]; /* 0 + 16 */ + % float intent_p1; % char vox_units[4]; /* 16 + 4 */ + % float intent_p2; % char cal_units[8]; /* 20 + 4 */ + % float intent_p3; % char cal_units[8]; /* 24 + 4 */ + % short int intent_code; % short int unused1; /* 28 + 2 */ + % short int datatype; /* 30 + 2 */ + % short int bitpix; /* 32 + 2 */ + % short int slice_start; % short int dim_un0; /* 34 + 2 */ + % float pixdim[8]; /* 36 + 32 */ + % /* + % pixdim[] specifies the voxel dimensions: + % pixdim[1] - voxel width + % pixdim[2] - voxel height + % pixdim[3] - interslice distance + % pixdim[4] - volume timing, in msec + % ..etc + % */ + % float vox_offset; /* 68 + 4 */ + % float scl_slope; % float roi_scale; /* 72 + 4 */ + % float scl_inter; % float funused1; /* 76 + 4 */ + % short slice_end; % float funused2; /* 80 + 2 */ + % char slice_code; % float funused2; /* 82 + 1 */ + % char xyzt_units; % float funused2; /* 83 + 1 */ + % float cal_max; /* 84 + 4 */ + % float cal_min; /* 88 + 4 */ + % float slice_duration; % int compressed; /* 92 + 4 */ + % float toffset; % int verified; /* 96 + 4 */ + % int glmax; /* 100 + 4 */ + % int glmin; /* 104 + 4 */ + % }; /* total=108 bytes */ + + fwrite(fid, dime.dim(1:8), 'int16'); + fwrite(fid, dime.intent_p1(1), 'float32'); + fwrite(fid, dime.intent_p2(1), 'float32'); + fwrite(fid, dime.intent_p3(1), 'float32'); + fwrite(fid, dime.intent_code(1), 'int16'); + fwrite(fid, dime.datatype(1), 'int16'); + fwrite(fid, dime.bitpix(1), 'int16'); + fwrite(fid, dime.slice_start(1), 'int16'); + fwrite(fid, dime.pixdim(1:8), 'float32'); + fwrite(fid, dime.vox_offset(1), 'float32'); + fwrite(fid, dime.scl_slope(1), 'float32'); + fwrite(fid, dime.scl_inter(1), 'float32'); + fwrite(fid, dime.slice_end(1), 'int16'); + fwrite(fid, dime.slice_code(1), 'uchar'); + fwrite(fid, dime.xyzt_units(1), 'uchar'); + fwrite(fid, dime.cal_max(1), 'float32'); + fwrite(fid, dime.cal_min(1), 'float32'); + fwrite(fid, dime.slice_duration(1), 'float32'); + fwrite(fid, dime.toffset(1), 'float32'); + fwrite(fid, dime.glmax(1), 'int32'); + fwrite(fid, dime.glmin(1), 'int32'); + + return; % image_dimension + + +%--------------------------------------------------------------------- +function data_history(fid, hist) + + % Original header structures + %struct data_history + % { /* off + size */ + % char descrip[80]; /* 0 + 80 */ + % char aux_file[24]; /* 80 + 24 */ + % short int qform_code; /* 104 + 2 */ + % short int sform_code; /* 106 + 2 */ + % float quatern_b; /* 108 + 4 */ + % float quatern_c; /* 112 + 4 */ + % float quatern_d; /* 116 + 4 */ + % float qoffset_x; /* 120 + 4 */ + % float qoffset_y; /* 124 + 4 */ + % float qoffset_z; /* 128 + 4 */ + % float srow_x[4]; /* 132 + 16 */ + % float srow_y[4]; /* 148 + 16 */ + % float srow_z[4]; /* 164 + 16 */ + % char intent_name[16]; /* 180 + 16 */ + % char magic[4]; % int smin; /* 196 + 4 */ + % }; /* total=200 bytes */ + + % descrip = sprintf('%-80s', hist.descrip); % 80 chars from left + % fwrite(fid, descrip(1:80), 'uchar'); + pad = zeros(1, 80-length(hist.descrip)); + hist.descrip = [hist.descrip char(pad)]; + fwrite(fid, hist.descrip(1:80), 'uchar'); + + % aux_file = sprintf('%-24s', hist.aux_file); % 24 chars from left + % fwrite(fid, aux_file(1:24), 'uchar'); + pad = zeros(1, 24-length(hist.aux_file)); + hist.aux_file = [hist.aux_file char(pad)]; + fwrite(fid, hist.aux_file(1:24), 'uchar'); + + fwrite(fid, hist.qform_code, 'int16'); + fwrite(fid, hist.sform_code, 'int16'); + fwrite(fid, hist.quatern_b, 'float32'); + fwrite(fid, hist.quatern_c, 'float32'); + fwrite(fid, hist.quatern_d, 'float32'); + fwrite(fid, hist.qoffset_x, 'float32'); + fwrite(fid, hist.qoffset_y, 'float32'); + fwrite(fid, hist.qoffset_z, 'float32'); + fwrite(fid, hist.srow_x(1:4), 'float32'); + fwrite(fid, hist.srow_y(1:4), 'float32'); + fwrite(fid, hist.srow_z(1:4), 'float32'); + + % intent_name = sprintf('%-16s', hist.intent_name); % 16 chars from left + % fwrite(fid, intent_name(1:16), 'uchar'); + pad = zeros(1, 16-length(hist.intent_name)); + hist.intent_name = [hist.intent_name char(pad)]; + fwrite(fid, hist.intent_name(1:16), 'uchar'); + + % magic = sprintf('%-4s', hist.magic); % 4 chars from left + % fwrite(fid, magic(1:4), 'uchar'); + pad = zeros(1, 4-length(hist.magic)); + hist.magic = [hist.magic char(pad)]; + fwrite(fid, hist.magic(1:4), 'uchar'); + + return; % data_history + diff --git a/matlab/save_untouch0_nii_hdr.m b/matlab/save_untouch0_nii_hdr.m index b812776..ba1f322 100644 --- a/matlab/save_untouch0_nii_hdr.m +++ b/matlab/save_untouch0_nii_hdr.m @@ -1,219 +1,219 @@ -% internal function - -% - Jimmy Shen (jimmy@rotman-baycrest.on.ca) - -function save_nii_hdr(hdr, fid) - - if ~isequal(hdr.hk.sizeof_hdr,348), - error('hdr.hk.sizeof_hdr must be 348.'); - end - - write_header(hdr, fid); - - return; % save_nii_hdr - - -%--------------------------------------------------------------------- -function write_header(hdr, fid) - - % Original header structures - % struct dsr /* dsr = hdr */ - % { - % struct header_key hk; /* 0 + 40 */ - % struct image_dimension dime; /* 40 + 108 */ - % struct data_history hist; /* 148 + 200 */ - % }; /* total= 348 bytes*/ - - header_key(fid, hdr.hk); - image_dimension(fid, hdr.dime); - data_history(fid, hdr.hist); - - % check the file size is 348 bytes - % - fbytes = ftell(fid); - - if ~isequal(fbytes,348), - msg = sprintf('Header size is not 348 bytes.'); - warning(msg); - end - - return; % write_header - - -%--------------------------------------------------------------------- -function header_key(fid, hk) - - fseek(fid,0,'bof'); - - % Original header structures - % struct header_key /* header key */ - % { /* off + size */ - % int sizeof_hdr /* 0 + 4 */ - % char data_type[10]; /* 4 + 10 */ - % char db_name[18]; /* 14 + 18 */ - % int extents; /* 32 + 4 */ - % short int session_error; /* 36 + 2 */ - % char regular; /* 38 + 1 */ - % char hkey_un0; /* 39 + 1 */ - % }; /* total=40 bytes */ - - fwrite(fid, hk.sizeof_hdr(1), 'int32'); % must be 348. - - % data_type = sprintf('%-10s',hk.data_type); % ensure it is 10 chars from left - % fwrite(fid, data_type(1:10), 'uchar'); - pad = zeros(1, 10-length(hk.data_type)); - hk.data_type = [hk.data_type char(pad)]; - fwrite(fid, hk.data_type(1:10), 'uchar'); - - % db_name = sprintf('%-18s', hk.db_name); % ensure it is 18 chars from left - % fwrite(fid, db_name(1:18), 'uchar'); - pad = zeros(1, 18-length(hk.db_name)); - hk.db_name = [hk.db_name char(pad)]; - fwrite(fid, hk.db_name(1:18), 'uchar'); - - fwrite(fid, hk.extents(1), 'int32'); - fwrite(fid, hk.session_error(1), 'int16'); - fwrite(fid, hk.regular(1), 'uchar'); - - fwrite(fid, hk.hkey_un0(1), 'uchar'); - - return; % header_key - - -%--------------------------------------------------------------------- -function image_dimension(fid, dime) - - %struct image_dimension - % { /* off + size */ - % short int dim[8]; /* 0 + 16 */ - % char vox_units[4]; /* 16 + 4 */ - % char cal_units[8]; /* 20 + 8 */ - % short int unused1; /* 28 + 2 */ - % short int datatype; /* 30 + 2 */ - % short int bitpix; /* 32 + 2 */ - % short int dim_un0; /* 34 + 2 */ - % float pixdim[8]; /* 36 + 32 */ - % /* - % pixdim[] specifies the voxel dimensions: - % pixdim[1] - voxel width - % pixdim[2] - voxel height - % pixdim[3] - interslice distance - % ..etc - % */ - % float vox_offset; /* 68 + 4 */ - % float roi_scale; /* 72 + 4 */ - % float funused1; /* 76 + 4 */ - % float funused2; /* 80 + 4 */ - % float cal_max; /* 84 + 4 */ - % float cal_min; /* 88 + 4 */ - % int compressed; /* 92 + 4 */ - % int verified; /* 96 + 4 */ - % int glmax; /* 100 + 4 */ - % int glmin; /* 104 + 4 */ - % }; /* total=108 bytes */ - - fwrite(fid, dime.dim(1:8), 'int16'); - - pad = zeros(1, 4-length(dime.vox_units)); - dime.vox_units = [dime.vox_units char(pad)]; - fwrite(fid, dime.vox_units(1:4), 'uchar'); - - pad = zeros(1, 8-length(dime.cal_units)); - dime.cal_units = [dime.cal_units char(pad)]; - fwrite(fid, dime.cal_units(1:8), 'uchar'); - - fwrite(fid, dime.unused1(1), 'int16'); - fwrite(fid, dime.datatype(1), 'int16'); - fwrite(fid, dime.bitpix(1), 'int16'); - fwrite(fid, dime.dim_un0(1), 'int16'); - fwrite(fid, dime.pixdim(1:8), 'float32'); - fwrite(fid, dime.vox_offset(1), 'float32'); - fwrite(fid, dime.roi_scale(1), 'float32'); - fwrite(fid, dime.funused1(1), 'float32'); - fwrite(fid, dime.funused2(1), 'float32'); - fwrite(fid, dime.cal_max(1), 'float32'); - fwrite(fid, dime.cal_min(1), 'float32'); - fwrite(fid, dime.compressed(1), 'int32'); - fwrite(fid, dime.verified(1), 'int32'); - fwrite(fid, dime.glmax(1), 'int32'); - fwrite(fid, dime.glmin(1), 'int32'); - - return; % image_dimension - - -%--------------------------------------------------------------------- -function data_history(fid, hist) - - % Original header structures - ANALYZE 7.5 - %struct data_history - % { /* off + size */ - % char descrip[80]; /* 0 + 80 */ - % char aux_file[24]; /* 80 + 24 */ - % char orient; /* 104 + 1 */ - % char originator[10]; /* 105 + 10 */ - % char generated[10]; /* 115 + 10 */ - % char scannum[10]; /* 125 + 10 */ - % char patient_id[10]; /* 135 + 10 */ - % char exp_date[10]; /* 145 + 10 */ - % char exp_time[10]; /* 155 + 10 */ - % char hist_un0[3]; /* 165 + 3 */ - % int views /* 168 + 4 */ - % int vols_added; /* 172 + 4 */ - % int start_field; /* 176 + 4 */ - % int field_skip; /* 180 + 4 */ - % int omax; /* 184 + 4 */ - % int omin; /* 188 + 4 */ - % int smax; /* 192 + 4 */ - % int smin; /* 196 + 4 */ - % }; /* total=200 bytes */ - - % descrip = sprintf('%-80s', hist.descrip); % 80 chars from left - % fwrite(fid, descrip(1:80), 'uchar'); - pad = zeros(1, 80-length(hist.descrip)); - hist.descrip = [hist.descrip char(pad)]; - fwrite(fid, hist.descrip(1:80), 'uchar'); - - % aux_file = sprintf('%-24s', hist.aux_file); % 24 chars from left - % fwrite(fid, aux_file(1:24), 'uchar'); - pad = zeros(1, 24-length(hist.aux_file)); - hist.aux_file = [hist.aux_file char(pad)]; - fwrite(fid, hist.aux_file(1:24), 'uchar'); - - fwrite(fid, hist.orient(1), 'uchar'); - fwrite(fid, hist.originator(1:5), 'int16'); - - pad = zeros(1, 10-length(hist.generated)); - hist.generated = [hist.generated char(pad)]; - fwrite(fid, hist.generated(1:10), 'uchar'); - - pad = zeros(1, 10-length(hist.scannum)); - hist.scannum = [hist.scannum char(pad)]; - fwrite(fid, hist.scannum(1:10), 'uchar'); - - pad = zeros(1, 10-length(hist.patient_id)); - hist.patient_id = [hist.patient_id char(pad)]; - fwrite(fid, hist.patient_id(1:10), 'uchar'); - - pad = zeros(1, 10-length(hist.exp_date)); - hist.exp_date = [hist.exp_date char(pad)]; - fwrite(fid, hist.exp_date(1:10), 'uchar'); - - pad = zeros(1, 10-length(hist.exp_time)); - hist.exp_time = [hist.exp_time char(pad)]; - fwrite(fid, hist.exp_time(1:10), 'uchar'); - - pad = zeros(1, 3-length(hist.hist_un0)); - hist.hist_un0 = [hist.hist_un0 char(pad)]; - fwrite(fid, hist.hist_un0(1:3), 'uchar'); - - fwrite(fid, hist.views(1), 'int32'); - fwrite(fid, hist.vols_added(1), 'int32'); - fwrite(fid, hist.start_field(1),'int32'); - fwrite(fid, hist.field_skip(1), 'int32'); - fwrite(fid, hist.omax(1), 'int32'); - fwrite(fid, hist.omin(1), 'int32'); - fwrite(fid, hist.smax(1), 'int32'); - fwrite(fid, hist.smin(1), 'int32'); - - return; % data_history - +% internal function + +% - Jimmy Shen (jimmy@rotman-baycrest.on.ca) + +function save_nii_hdr(hdr, fid) + + if ~isequal(hdr.hk.sizeof_hdr,348), + error('hdr.hk.sizeof_hdr must be 348.'); + end + + write_header(hdr, fid); + + return; % save_nii_hdr + + +%--------------------------------------------------------------------- +function write_header(hdr, fid) + + % Original header structures + % struct dsr /* dsr = hdr */ + % { + % struct header_key hk; /* 0 + 40 */ + % struct image_dimension dime; /* 40 + 108 */ + % struct data_history hist; /* 148 + 200 */ + % }; /* total= 348 bytes*/ + + header_key(fid, hdr.hk); + image_dimension(fid, hdr.dime); + data_history(fid, hdr.hist); + + % check the file size is 348 bytes + % + fbytes = ftell(fid); + + if ~isequal(fbytes,348), + msg = sprintf('Header size is not 348 bytes.'); + warning(msg); + end + + return; % write_header + + +%--------------------------------------------------------------------- +function header_key(fid, hk) + + fseek(fid,0,'bof'); + + % Original header structures + % struct header_key /* header key */ + % { /* off + size */ + % int sizeof_hdr /* 0 + 4 */ + % char data_type[10]; /* 4 + 10 */ + % char db_name[18]; /* 14 + 18 */ + % int extents; /* 32 + 4 */ + % short int session_error; /* 36 + 2 */ + % char regular; /* 38 + 1 */ + % char hkey_un0; /* 39 + 1 */ + % }; /* total=40 bytes */ + + fwrite(fid, hk.sizeof_hdr(1), 'int32'); % must be 348. + + % data_type = sprintf('%-10s',hk.data_type); % ensure it is 10 chars from left + % fwrite(fid, data_type(1:10), 'uchar'); + pad = zeros(1, 10-length(hk.data_type)); + hk.data_type = [hk.data_type char(pad)]; + fwrite(fid, hk.data_type(1:10), 'uchar'); + + % db_name = sprintf('%-18s', hk.db_name); % ensure it is 18 chars from left + % fwrite(fid, db_name(1:18), 'uchar'); + pad = zeros(1, 18-length(hk.db_name)); + hk.db_name = [hk.db_name char(pad)]; + fwrite(fid, hk.db_name(1:18), 'uchar'); + + fwrite(fid, hk.extents(1), 'int32'); + fwrite(fid, hk.session_error(1), 'int16'); + fwrite(fid, hk.regular(1), 'uchar'); + + fwrite(fid, hk.hkey_un0(1), 'uchar'); + + return; % header_key + + +%--------------------------------------------------------------------- +function image_dimension(fid, dime) + + %struct image_dimension + % { /* off + size */ + % short int dim[8]; /* 0 + 16 */ + % char vox_units[4]; /* 16 + 4 */ + % char cal_units[8]; /* 20 + 8 */ + % short int unused1; /* 28 + 2 */ + % short int datatype; /* 30 + 2 */ + % short int bitpix; /* 32 + 2 */ + % short int dim_un0; /* 34 + 2 */ + % float pixdim[8]; /* 36 + 32 */ + % /* + % pixdim[] specifies the voxel dimensions: + % pixdim[1] - voxel width + % pixdim[2] - voxel height + % pixdim[3] - interslice distance + % ..etc + % */ + % float vox_offset; /* 68 + 4 */ + % float roi_scale; /* 72 + 4 */ + % float funused1; /* 76 + 4 */ + % float funused2; /* 80 + 4 */ + % float cal_max; /* 84 + 4 */ + % float cal_min; /* 88 + 4 */ + % int compressed; /* 92 + 4 */ + % int verified; /* 96 + 4 */ + % int glmax; /* 100 + 4 */ + % int glmin; /* 104 + 4 */ + % }; /* total=108 bytes */ + + fwrite(fid, dime.dim(1:8), 'int16'); + + pad = zeros(1, 4-length(dime.vox_units)); + dime.vox_units = [dime.vox_units char(pad)]; + fwrite(fid, dime.vox_units(1:4), 'uchar'); + + pad = zeros(1, 8-length(dime.cal_units)); + dime.cal_units = [dime.cal_units char(pad)]; + fwrite(fid, dime.cal_units(1:8), 'uchar'); + + fwrite(fid, dime.unused1(1), 'int16'); + fwrite(fid, dime.datatype(1), 'int16'); + fwrite(fid, dime.bitpix(1), 'int16'); + fwrite(fid, dime.dim_un0(1), 'int16'); + fwrite(fid, dime.pixdim(1:8), 'float32'); + fwrite(fid, dime.vox_offset(1), 'float32'); + fwrite(fid, dime.roi_scale(1), 'float32'); + fwrite(fid, dime.funused1(1), 'float32'); + fwrite(fid, dime.funused2(1), 'float32'); + fwrite(fid, dime.cal_max(1), 'float32'); + fwrite(fid, dime.cal_min(1), 'float32'); + fwrite(fid, dime.compressed(1), 'int32'); + fwrite(fid, dime.verified(1), 'int32'); + fwrite(fid, dime.glmax(1), 'int32'); + fwrite(fid, dime.glmin(1), 'int32'); + + return; % image_dimension + + +%--------------------------------------------------------------------- +function data_history(fid, hist) + + % Original header structures - ANALYZE 7.5 + %struct data_history + % { /* off + size */ + % char descrip[80]; /* 0 + 80 */ + % char aux_file[24]; /* 80 + 24 */ + % char orient; /* 104 + 1 */ + % char originator[10]; /* 105 + 10 */ + % char generated[10]; /* 115 + 10 */ + % char scannum[10]; /* 125 + 10 */ + % char patient_id[10]; /* 135 + 10 */ + % char exp_date[10]; /* 145 + 10 */ + % char exp_time[10]; /* 155 + 10 */ + % char hist_un0[3]; /* 165 + 3 */ + % int views /* 168 + 4 */ + % int vols_added; /* 172 + 4 */ + % int start_field; /* 176 + 4 */ + % int field_skip; /* 180 + 4 */ + % int omax; /* 184 + 4 */ + % int omin; /* 188 + 4 */ + % int smax; /* 192 + 4 */ + % int smin; /* 196 + 4 */ + % }; /* total=200 bytes */ + + % descrip = sprintf('%-80s', hist.descrip); % 80 chars from left + % fwrite(fid, descrip(1:80), 'uchar'); + pad = zeros(1, 80-length(hist.descrip)); + hist.descrip = [hist.descrip char(pad)]; + fwrite(fid, hist.descrip(1:80), 'uchar'); + + % aux_file = sprintf('%-24s', hist.aux_file); % 24 chars from left + % fwrite(fid, aux_file(1:24), 'uchar'); + pad = zeros(1, 24-length(hist.aux_file)); + hist.aux_file = [hist.aux_file char(pad)]; + fwrite(fid, hist.aux_file(1:24), 'uchar'); + + fwrite(fid, hist.orient(1), 'uchar'); + fwrite(fid, hist.originator(1:5), 'int16'); + + pad = zeros(1, 10-length(hist.generated)); + hist.generated = [hist.generated char(pad)]; + fwrite(fid, hist.generated(1:10), 'uchar'); + + pad = zeros(1, 10-length(hist.scannum)); + hist.scannum = [hist.scannum char(pad)]; + fwrite(fid, hist.scannum(1:10), 'uchar'); + + pad = zeros(1, 10-length(hist.patient_id)); + hist.patient_id = [hist.patient_id char(pad)]; + fwrite(fid, hist.patient_id(1:10), 'uchar'); + + pad = zeros(1, 10-length(hist.exp_date)); + hist.exp_date = [hist.exp_date char(pad)]; + fwrite(fid, hist.exp_date(1:10), 'uchar'); + + pad = zeros(1, 10-length(hist.exp_time)); + hist.exp_time = [hist.exp_time char(pad)]; + fwrite(fid, hist.exp_time(1:10), 'uchar'); + + pad = zeros(1, 3-length(hist.hist_un0)); + hist.hist_un0 = [hist.hist_un0 char(pad)]; + fwrite(fid, hist.hist_un0(1:3), 'uchar'); + + fwrite(fid, hist.views(1), 'int32'); + fwrite(fid, hist.vols_added(1), 'int32'); + fwrite(fid, hist.start_field(1),'int32'); + fwrite(fid, hist.field_skip(1), 'int32'); + fwrite(fid, hist.omax(1), 'int32'); + fwrite(fid, hist.omin(1), 'int32'); + fwrite(fid, hist.smax(1), 'int32'); + fwrite(fid, hist.smin(1), 'int32'); + + return; % data_history + diff --git a/matlab/save_untouch_nii.m b/matlab/save_untouch_nii.m index c0d5dc0..0fcf66a 100644 --- a/matlab/save_untouch_nii.m +++ b/matlab/save_untouch_nii.m @@ -1,197 +1,197 @@ -% Save NIFTI or ANALYZE dataset that is loaded by "load_untouch_nii.m". -% The output image format and file extension will be the same as the -% input one (NIFTI.nii, NIFTI.img or ANALYZE.img). Therefore, any file -% extension that you specified will be ignored. -% -% Usage: save_untouch_nii(nii, filename) -% -% nii - nii structure that is loaded by "load_untouch_nii.m" -% -% filename - NIFTI or ANALYZE file name. -% -% - Jimmy Shen (jimmy@rotman-baycrest.on.ca) -% -function save_untouch_nii(nii, filename) - - if ~exist('nii','var') | isempty(nii) | ~isfield(nii,'hdr') | ... - ~isfield(nii,'img') | ~exist('filename','var') | isempty(filename) - - error('Usage: save_untouch_nii(nii, filename)'); - end - - if ~isfield(nii,'untouch') | nii.untouch == 0 - error('Usage: please use ''save_nii.m'' for the modified structure.'); - end - - if isfield(nii.hdr.hist,'magic') & strcmp(nii.hdr.hist.magic(1:3),'ni1') - filetype = 1; - elseif isfield(nii.hdr.hist,'magic') & strcmp(nii.hdr.hist.magic(1:3),'n+1') - filetype = 2; - else - filetype = 0; - end - - [p,f] = fileparts(filename); - fileprefix = fullfile(p, f); - - write_nii(nii, filetype, fileprefix); - -% % So earlier versions of SPM can also open it with correct originator - % % - % if filetype == 0 - % M=[[diag(nii.hdr.dime.pixdim(2:4)) -[nii.hdr.hist.originator(1:3).*nii.hdr.dime.pixdim(2:4)]'];[0 0 0 1]]; - % save(fileprefix, 'M'); -% elseif filetype == 1 - % M=[]; - % save(fileprefix, 'M'); - %end - - return % save_untouch_nii - - -%----------------------------------------------------------------------------------- -function write_nii(nii, filetype, fileprefix) - - hdr = nii.hdr; - - if isfield(nii,'ext') & ~isempty(nii.ext) - ext = nii.ext; - [ext, esize_total] = verify_nii_ext(ext); - else - ext = []; - end - - switch double(hdr.dime.datatype), - case 1, - hdr.dime.bitpix = int16(1 ); precision = 'ubit1'; - case 2, - hdr.dime.bitpix = int16(8 ); precision = 'uint8'; - case 4, - hdr.dime.bitpix = int16(16); precision = 'int16'; - case 8, - hdr.dime.bitpix = int16(32); precision = 'int32'; - case 16, - hdr.dime.bitpix = int16(32); precision = 'float32'; - case 32, - hdr.dime.bitpix = int16(64); precision = 'float32'; - case 64, - hdr.dime.bitpix = int16(64); precision = 'float64'; - case 128, - hdr.dime.bitpix = int16(24); precision = 'uint8'; - case 256 - hdr.dime.bitpix = int16(8 ); precision = 'int8'; - case 512 - hdr.dime.bitpix = int16(16); precision = 'uint16'; - case 768 - hdr.dime.bitpix = int16(32); precision = 'uint32'; - case 1024 - hdr.dime.bitpix = int16(64); precision = 'int64'; - case 1280 - hdr.dime.bitpix = int16(64); precision = 'uint64'; - case 1792, - hdr.dime.bitpix = int16(128); precision = 'float64'; - otherwise - error('This datatype is not supported'); - end - -% hdr.dime.glmax = round(double(max(nii.img(:)))); - % hdr.dime.glmin = round(double(min(nii.img(:)))); - - if filetype == 2 - fid = fopen(sprintf('%s.nii',fileprefix),'w'); - - if fid < 0, - msg = sprintf('Cannot open file %s.nii.',fileprefix); - error(msg); - end - - hdr.dime.vox_offset = 352; - - if ~isempty(ext) - hdr.dime.vox_offset = hdr.dime.vox_offset + esize_total; - end - - hdr.hist.magic = 'n+1'; - save_untouch_nii_hdr(hdr, fid); - - if ~isempty(ext) - save_nii_ext(ext, fid); - end - elseif filetype == 1 - fid = fopen(sprintf('%s.hdr',fileprefix),'w'); - - if fid < 0, - msg = sprintf('Cannot open file %s.hdr.',fileprefix); - error(msg); - end - - hdr.dime.vox_offset = 0; - hdr.hist.magic = 'ni1'; - save_untouch_nii_hdr(hdr, fid); - - if ~isempty(ext) - save_nii_ext(ext, fid); - end - - fclose(fid); - fid = fopen(sprintf('%s.img',fileprefix),'w'); - else - fid = fopen(sprintf('%s.hdr',fileprefix),'w'); - - if fid < 0, - msg = sprintf('Cannot open file %s.hdr.',fileprefix); - error(msg); - end - - save_untouch0_nii_hdr(hdr, fid); - - fclose(fid); - fid = fopen(sprintf('%s.img',fileprefix),'w'); - end - - ScanDim = double(hdr.dime.dim(5)); % t - SliceDim = double(hdr.dime.dim(4)); % z - RowDim = double(hdr.dime.dim(3)); % y - PixelDim = double(hdr.dime.dim(2)); % x - SliceSz = double(hdr.dime.pixdim(4)); - RowSz = double(hdr.dime.pixdim(3)); - PixelSz = double(hdr.dime.pixdim(2)); - - x = 1:PixelDim; - - if filetype == 2 & isempty(ext) - skip_bytes = double(hdr.dime.vox_offset) - 348; - else - skip_bytes = 0; - end - - if double(hdr.dime.datatype) == 128 - - % RGB planes are expected to be in the 4th dimension of nii.img - % - if(size(nii.img,4)~=3) - error(['The NII structure does not appear to have 3 RGB color planes in the 4th dimension']); - end - - nii.img = permute(nii.img, [4 1 2 3 5 6 7 8]); - end - - % For complex float32 or complex float64, voxel values - % include [real, imag] - % - if hdr.dime.datatype == 32 | hdr.dime.datatype == 1792 - real_img = real(nii.img(:))'; - nii.img = imag(nii.img(:))'; - nii.img = [real_img; nii.img]; - end - - if skip_bytes - fwrite(fid, zeros(1,skip_bytes), 'uint8'); - end - - fwrite(fid, nii.img, precision); -% fwrite(fid, nii.img, precision, skip_bytes); % error using skip - fclose(fid); - - return; % write_nii - +% Save NIFTI or ANALYZE dataset that is loaded by "load_untouch_nii.m". +% The output image format and file extension will be the same as the +% input one (NIFTI.nii, NIFTI.img or ANALYZE.img). Therefore, any file +% extension that you specified will be ignored. +% +% Usage: save_untouch_nii(nii, filename) +% +% nii - nii structure that is loaded by "load_untouch_nii.m" +% +% filename - NIFTI or ANALYZE file name. +% +% - Jimmy Shen (jimmy@rotman-baycrest.on.ca) +% +function save_untouch_nii(nii, filename) + + if ~exist('nii','var') | isempty(nii) | ~isfield(nii,'hdr') | ... + ~isfield(nii,'img') | ~exist('filename','var') | isempty(filename) + + error('Usage: save_untouch_nii(nii, filename)'); + end + + if ~isfield(nii,'untouch') | nii.untouch == 0 + error('Usage: please use ''save_nii.m'' for the modified structure.'); + end + + if isfield(nii.hdr.hist,'magic') & strcmp(nii.hdr.hist.magic(1:3),'ni1') + filetype = 1; + elseif isfield(nii.hdr.hist,'magic') & strcmp(nii.hdr.hist.magic(1:3),'n+1') + filetype = 2; + else + filetype = 0; + end + + [p,f] = fileparts(filename); + fileprefix = fullfile(p, f); + + write_nii(nii, filetype, fileprefix); + +% % So earlier versions of SPM can also open it with correct originator + % % + % if filetype == 0 + % M=[[diag(nii.hdr.dime.pixdim(2:4)) -[nii.hdr.hist.originator(1:3).*nii.hdr.dime.pixdim(2:4)]'];[0 0 0 1]]; + % save(fileprefix, 'M'); +% elseif filetype == 1 + % M=[]; + % save(fileprefix, 'M'); + %end + + return % save_untouch_nii + + +%----------------------------------------------------------------------------------- +function write_nii(nii, filetype, fileprefix) + + hdr = nii.hdr; + + if isfield(nii,'ext') & ~isempty(nii.ext) + ext = nii.ext; + [ext, esize_total] = verify_nii_ext(ext); + else + ext = []; + end + + switch double(hdr.dime.datatype), + case 1, + hdr.dime.bitpix = int16(1 ); precision = 'ubit1'; + case 2, + hdr.dime.bitpix = int16(8 ); precision = 'uint8'; + case 4, + hdr.dime.bitpix = int16(16); precision = 'int16'; + case 8, + hdr.dime.bitpix = int16(32); precision = 'int32'; + case 16, + hdr.dime.bitpix = int16(32); precision = 'float32'; + case 32, + hdr.dime.bitpix = int16(64); precision = 'float32'; + case 64, + hdr.dime.bitpix = int16(64); precision = 'float64'; + case 128, + hdr.dime.bitpix = int16(24); precision = 'uint8'; + case 256 + hdr.dime.bitpix = int16(8 ); precision = 'int8'; + case 512 + hdr.dime.bitpix = int16(16); precision = 'uint16'; + case 768 + hdr.dime.bitpix = int16(32); precision = 'uint32'; + case 1024 + hdr.dime.bitpix = int16(64); precision = 'int64'; + case 1280 + hdr.dime.bitpix = int16(64); precision = 'uint64'; + case 1792, + hdr.dime.bitpix = int16(128); precision = 'float64'; + otherwise + error('This datatype is not supported'); + end + +% hdr.dime.glmax = round(double(max(nii.img(:)))); + % hdr.dime.glmin = round(double(min(nii.img(:)))); + + if filetype == 2 + fid = fopen(sprintf('%s.nii',fileprefix),'w'); + + if fid < 0, + msg = sprintf('Cannot open file %s.nii.',fileprefix); + error(msg); + end + + hdr.dime.vox_offset = 352; + + if ~isempty(ext) + hdr.dime.vox_offset = hdr.dime.vox_offset + esize_total; + end + + hdr.hist.magic = 'n+1'; + save_untouch_nii_hdr(hdr, fid); + + if ~isempty(ext) + save_nii_ext(ext, fid); + end + elseif filetype == 1 + fid = fopen(sprintf('%s.hdr',fileprefix),'w'); + + if fid < 0, + msg = sprintf('Cannot open file %s.hdr.',fileprefix); + error(msg); + end + + hdr.dime.vox_offset = 0; + hdr.hist.magic = 'ni1'; + save_untouch_nii_hdr(hdr, fid); + + if ~isempty(ext) + save_nii_ext(ext, fid); + end + + fclose(fid); + fid = fopen(sprintf('%s.img',fileprefix),'w'); + else + fid = fopen(sprintf('%s.hdr',fileprefix),'w'); + + if fid < 0, + msg = sprintf('Cannot open file %s.hdr.',fileprefix); + error(msg); + end + + save_untouch0_nii_hdr(hdr, fid); + + fclose(fid); + fid = fopen(sprintf('%s.img',fileprefix),'w'); + end + + ScanDim = double(hdr.dime.dim(5)); % t + SliceDim = double(hdr.dime.dim(4)); % z + RowDim = double(hdr.dime.dim(3)); % y + PixelDim = double(hdr.dime.dim(2)); % x + SliceSz = double(hdr.dime.pixdim(4)); + RowSz = double(hdr.dime.pixdim(3)); + PixelSz = double(hdr.dime.pixdim(2)); + + x = 1:PixelDim; + + if filetype == 2 & isempty(ext) + skip_bytes = double(hdr.dime.vox_offset) - 348; + else + skip_bytes = 0; + end + + if double(hdr.dime.datatype) == 128 + + % RGB planes are expected to be in the 4th dimension of nii.img + % + if(size(nii.img,4)~=3) + error(['The NII structure does not appear to have 3 RGB color planes in the 4th dimension']); + end + + nii.img = permute(nii.img, [4 1 2 3 5 6 7 8]); + end + + % For complex float32 or complex float64, voxel values + % include [real, imag] + % + if hdr.dime.datatype == 32 | hdr.dime.datatype == 1792 + real_img = real(nii.img(:))'; + nii.img = imag(nii.img(:))'; + nii.img = [real_img; nii.img]; + end + + if skip_bytes + fwrite(fid, zeros(1,skip_bytes), 'uint8'); + end + + fwrite(fid, nii.img, precision); +% fwrite(fid, nii.img, precision, skip_bytes); % error using skip + fclose(fid); + + return; % write_nii + diff --git a/matlab/save_untouch_nii_hdr.m b/matlab/save_untouch_nii_hdr.m index 9ee0fd6..33fa9ed 100644 --- a/matlab/save_untouch_nii_hdr.m +++ b/matlab/save_untouch_nii_hdr.m @@ -1,207 +1,207 @@ -% internal function - -% - Jimmy Shen (jimmy@rotman-baycrest.on.ca) - -function save_nii_hdr(hdr, fid) - - if ~isequal(hdr.hk.sizeof_hdr,348), - error('hdr.hk.sizeof_hdr must be 348.'); - end - - write_header(hdr, fid); - - return; % save_nii_hdr - - -%--------------------------------------------------------------------- -function write_header(hdr, fid) - - % Original header structures - % struct dsr /* dsr = hdr */ - % { - % struct header_key hk; /* 0 + 40 */ - % struct image_dimension dime; /* 40 + 108 */ - % struct data_history hist; /* 148 + 200 */ - % }; /* total= 348 bytes*/ - - header_key(fid, hdr.hk); - image_dimension(fid, hdr.dime); - data_history(fid, hdr.hist); - - % check the file size is 348 bytes - % - fbytes = ftell(fid); - - if ~isequal(fbytes,348), - msg = sprintf('Header size is not 348 bytes.'); - warning(msg); - end - - return; % write_header - - -%--------------------------------------------------------------------- -function header_key(fid, hk) - - fseek(fid,0,'bof'); - - % Original header structures - % struct header_key /* header key */ - % { /* off + size */ - % int sizeof_hdr /* 0 + 4 */ - % char data_type[10]; /* 4 + 10 */ - % char db_name[18]; /* 14 + 18 */ - % int extents; /* 32 + 4 */ - % short int session_error; /* 36 + 2 */ - % char regular; /* 38 + 1 */ - % char dim_info; % char hkey_un0; /* 39 + 1 */ - % }; /* total=40 bytes */ - - fwrite(fid, hk.sizeof_hdr(1), 'int32'); % must be 348. - - % data_type = sprintf('%-10s',hk.data_type); % ensure it is 10 chars from left - % fwrite(fid, data_type(1:10), 'uchar'); - pad = zeros(1, 10-length(hk.data_type)); - hk.data_type = [hk.data_type char(pad)]; - fwrite(fid, hk.data_type(1:10), 'uchar'); - - % db_name = sprintf('%-18s', hk.db_name); % ensure it is 18 chars from left - % fwrite(fid, db_name(1:18), 'uchar'); - pad = zeros(1, 18-length(hk.db_name)); - hk.db_name = [hk.db_name char(pad)]; - fwrite(fid, hk.db_name(1:18), 'uchar'); - - fwrite(fid, hk.extents(1), 'int32'); - fwrite(fid, hk.session_error(1), 'int16'); - fwrite(fid, hk.regular(1), 'uchar'); % might be uint8 - - % fwrite(fid, hk.hkey_un0(1), 'uchar'); - % fwrite(fid, hk.hkey_un0(1), 'uint8'); - fwrite(fid, hk.dim_info(1), 'uchar'); - - return; % header_key - - -%--------------------------------------------------------------------- -function image_dimension(fid, dime) - - % Original header structures - % struct image_dimension - % { /* off + size */ - % short int dim[8]; /* 0 + 16 */ - % float intent_p1; % char vox_units[4]; /* 16 + 4 */ - % float intent_p2; % char cal_units[8]; /* 20 + 4 */ - % float intent_p3; % char cal_units[8]; /* 24 + 4 */ - % short int intent_code; % short int unused1; /* 28 + 2 */ - % short int datatype; /* 30 + 2 */ - % short int bitpix; /* 32 + 2 */ - % short int slice_start; % short int dim_un0; /* 34 + 2 */ - % float pixdim[8]; /* 36 + 32 */ - % /* - % pixdim[] specifies the voxel dimensions: - % pixdim[1] - voxel width - % pixdim[2] - voxel height - % pixdim[3] - interslice distance - % pixdim[4] - volume timing, in msec - % ..etc - % */ - % float vox_offset; /* 68 + 4 */ - % float scl_slope; % float roi_scale; /* 72 + 4 */ - % float scl_inter; % float funused1; /* 76 + 4 */ - % short slice_end; % float funused2; /* 80 + 2 */ - % char slice_code; % float funused2; /* 82 + 1 */ - % char xyzt_units; % float funused2; /* 83 + 1 */ - % float cal_max; /* 84 + 4 */ - % float cal_min; /* 88 + 4 */ - % float slice_duration; % int compressed; /* 92 + 4 */ - % float toffset; % int verified; /* 96 + 4 */ - % int glmax; /* 100 + 4 */ - % int glmin; /* 104 + 4 */ - % }; /* total=108 bytes */ - - fwrite(fid, dime.dim(1:8), 'int16'); - fwrite(fid, dime.intent_p1(1), 'float32'); - fwrite(fid, dime.intent_p2(1), 'float32'); - fwrite(fid, dime.intent_p3(1), 'float32'); - fwrite(fid, dime.intent_code(1), 'int16'); - fwrite(fid, dime.datatype(1), 'int16'); - fwrite(fid, dime.bitpix(1), 'int16'); - fwrite(fid, dime.slice_start(1), 'int16'); - fwrite(fid, dime.pixdim(1:8), 'float32'); - fwrite(fid, dime.vox_offset(1), 'float32'); - fwrite(fid, dime.scl_slope(1), 'float32'); - fwrite(fid, dime.scl_inter(1), 'float32'); - fwrite(fid, dime.slice_end(1), 'int16'); - fwrite(fid, dime.slice_code(1), 'uchar'); - fwrite(fid, dime.xyzt_units(1), 'uchar'); - fwrite(fid, dime.cal_max(1), 'float32'); - fwrite(fid, dime.cal_min(1), 'float32'); - fwrite(fid, dime.slice_duration(1), 'float32'); - fwrite(fid, dime.toffset(1), 'float32'); - fwrite(fid, dime.glmax(1), 'int32'); - fwrite(fid, dime.glmin(1), 'int32'); - - return; % image_dimension - - -%--------------------------------------------------------------------- -function data_history(fid, hist) - - % Original header structures - %struct data_history - % { /* off + size */ - % char descrip[80]; /* 0 + 80 */ - % char aux_file[24]; /* 80 + 24 */ - % short int qform_code; /* 104 + 2 */ - % short int sform_code; /* 106 + 2 */ - % float quatern_b; /* 108 + 4 */ - % float quatern_c; /* 112 + 4 */ - % float quatern_d; /* 116 + 4 */ - % float qoffset_x; /* 120 + 4 */ - % float qoffset_y; /* 124 + 4 */ - % float qoffset_z; /* 128 + 4 */ - % float srow_x[4]; /* 132 + 16 */ - % float srow_y[4]; /* 148 + 16 */ - % float srow_z[4]; /* 164 + 16 */ - % char intent_name[16]; /* 180 + 16 */ - % char magic[4]; % int smin; /* 196 + 4 */ - % }; /* total=200 bytes */ - - % descrip = sprintf('%-80s', hist.descrip); % 80 chars from left - % fwrite(fid, descrip(1:80), 'uchar'); - pad = zeros(1, 80-length(hist.descrip)); - hist.descrip = [hist.descrip char(pad)]; - fwrite(fid, hist.descrip(1:80), 'uchar'); - - % aux_file = sprintf('%-24s', hist.aux_file); % 24 chars from left - % fwrite(fid, aux_file(1:24), 'uchar'); - pad = zeros(1, 24-length(hist.aux_file)); - hist.aux_file = [hist.aux_file char(pad)]; - fwrite(fid, hist.aux_file(1:24), 'uchar'); - - fwrite(fid, hist.qform_code, 'int16'); - fwrite(fid, hist.sform_code, 'int16'); - fwrite(fid, hist.quatern_b, 'float32'); - fwrite(fid, hist.quatern_c, 'float32'); - fwrite(fid, hist.quatern_d, 'float32'); - fwrite(fid, hist.qoffset_x, 'float32'); - fwrite(fid, hist.qoffset_y, 'float32'); - fwrite(fid, hist.qoffset_z, 'float32'); - fwrite(fid, hist.srow_x(1:4), 'float32'); - fwrite(fid, hist.srow_y(1:4), 'float32'); - fwrite(fid, hist.srow_z(1:4), 'float32'); - - % intent_name = sprintf('%-16s', hist.intent_name); % 16 chars from left - % fwrite(fid, intent_name(1:16), 'uchar'); - pad = zeros(1, 16-length(hist.intent_name)); - hist.intent_name = [hist.intent_name char(pad)]; - fwrite(fid, hist.intent_name(1:16), 'uchar'); - - % magic = sprintf('%-4s', hist.magic); % 4 chars from left - % fwrite(fid, magic(1:4), 'uchar'); - pad = zeros(1, 4-length(hist.magic)); - hist.magic = [hist.magic char(pad)]; - fwrite(fid, hist.magic(1:4), 'uchar'); - - return; % data_history - +% internal function + +% - Jimmy Shen (jimmy@rotman-baycrest.on.ca) + +function save_nii_hdr(hdr, fid) + + if ~isequal(hdr.hk.sizeof_hdr,348), + error('hdr.hk.sizeof_hdr must be 348.'); + end + + write_header(hdr, fid); + + return; % save_nii_hdr + + +%--------------------------------------------------------------------- +function write_header(hdr, fid) + + % Original header structures + % struct dsr /* dsr = hdr */ + % { + % struct header_key hk; /* 0 + 40 */ + % struct image_dimension dime; /* 40 + 108 */ + % struct data_history hist; /* 148 + 200 */ + % }; /* total= 348 bytes*/ + + header_key(fid, hdr.hk); + image_dimension(fid, hdr.dime); + data_history(fid, hdr.hist); + + % check the file size is 348 bytes + % + fbytes = ftell(fid); + + if ~isequal(fbytes,348), + msg = sprintf('Header size is not 348 bytes.'); + warning(msg); + end + + return; % write_header + + +%--------------------------------------------------------------------- +function header_key(fid, hk) + + fseek(fid,0,'bof'); + + % Original header structures + % struct header_key /* header key */ + % { /* off + size */ + % int sizeof_hdr /* 0 + 4 */ + % char data_type[10]; /* 4 + 10 */ + % char db_name[18]; /* 14 + 18 */ + % int extents; /* 32 + 4 */ + % short int session_error; /* 36 + 2 */ + % char regular; /* 38 + 1 */ + % char dim_info; % char hkey_un0; /* 39 + 1 */ + % }; /* total=40 bytes */ + + fwrite(fid, hk.sizeof_hdr(1), 'int32'); % must be 348. + + % data_type = sprintf('%-10s',hk.data_type); % ensure it is 10 chars from left + % fwrite(fid, data_type(1:10), 'uchar'); + pad = zeros(1, 10-length(hk.data_type)); + hk.data_type = [hk.data_type char(pad)]; + fwrite(fid, hk.data_type(1:10), 'uchar'); + + % db_name = sprintf('%-18s', hk.db_name); % ensure it is 18 chars from left + % fwrite(fid, db_name(1:18), 'uchar'); + pad = zeros(1, 18-length(hk.db_name)); + hk.db_name = [hk.db_name char(pad)]; + fwrite(fid, hk.db_name(1:18), 'uchar'); + + fwrite(fid, hk.extents(1), 'int32'); + fwrite(fid, hk.session_error(1), 'int16'); + fwrite(fid, hk.regular(1), 'uchar'); % might be uint8 + + % fwrite(fid, hk.hkey_un0(1), 'uchar'); + % fwrite(fid, hk.hkey_un0(1), 'uint8'); + fwrite(fid, hk.dim_info(1), 'uchar'); + + return; % header_key + + +%--------------------------------------------------------------------- +function image_dimension(fid, dime) + + % Original header structures + % struct image_dimension + % { /* off + size */ + % short int dim[8]; /* 0 + 16 */ + % float intent_p1; % char vox_units[4]; /* 16 + 4 */ + % float intent_p2; % char cal_units[8]; /* 20 + 4 */ + % float intent_p3; % char cal_units[8]; /* 24 + 4 */ + % short int intent_code; % short int unused1; /* 28 + 2 */ + % short int datatype; /* 30 + 2 */ + % short int bitpix; /* 32 + 2 */ + % short int slice_start; % short int dim_un0; /* 34 + 2 */ + % float pixdim[8]; /* 36 + 32 */ + % /* + % pixdim[] specifies the voxel dimensions: + % pixdim[1] - voxel width + % pixdim[2] - voxel height + % pixdim[3] - interslice distance + % pixdim[4] - volume timing, in msec + % ..etc + % */ + % float vox_offset; /* 68 + 4 */ + % float scl_slope; % float roi_scale; /* 72 + 4 */ + % float scl_inter; % float funused1; /* 76 + 4 */ + % short slice_end; % float funused2; /* 80 + 2 */ + % char slice_code; % float funused2; /* 82 + 1 */ + % char xyzt_units; % float funused2; /* 83 + 1 */ + % float cal_max; /* 84 + 4 */ + % float cal_min; /* 88 + 4 */ + % float slice_duration; % int compressed; /* 92 + 4 */ + % float toffset; % int verified; /* 96 + 4 */ + % int glmax; /* 100 + 4 */ + % int glmin; /* 104 + 4 */ + % }; /* total=108 bytes */ + + fwrite(fid, dime.dim(1:8), 'int16'); + fwrite(fid, dime.intent_p1(1), 'float32'); + fwrite(fid, dime.intent_p2(1), 'float32'); + fwrite(fid, dime.intent_p3(1), 'float32'); + fwrite(fid, dime.intent_code(1), 'int16'); + fwrite(fid, dime.datatype(1), 'int16'); + fwrite(fid, dime.bitpix(1), 'int16'); + fwrite(fid, dime.slice_start(1), 'int16'); + fwrite(fid, dime.pixdim(1:8), 'float32'); + fwrite(fid, dime.vox_offset(1), 'float32'); + fwrite(fid, dime.scl_slope(1), 'float32'); + fwrite(fid, dime.scl_inter(1), 'float32'); + fwrite(fid, dime.slice_end(1), 'int16'); + fwrite(fid, dime.slice_code(1), 'uchar'); + fwrite(fid, dime.xyzt_units(1), 'uchar'); + fwrite(fid, dime.cal_max(1), 'float32'); + fwrite(fid, dime.cal_min(1), 'float32'); + fwrite(fid, dime.slice_duration(1), 'float32'); + fwrite(fid, dime.toffset(1), 'float32'); + fwrite(fid, dime.glmax(1), 'int32'); + fwrite(fid, dime.glmin(1), 'int32'); + + return; % image_dimension + + +%--------------------------------------------------------------------- +function data_history(fid, hist) + + % Original header structures + %struct data_history + % { /* off + size */ + % char descrip[80]; /* 0 + 80 */ + % char aux_file[24]; /* 80 + 24 */ + % short int qform_code; /* 104 + 2 */ + % short int sform_code; /* 106 + 2 */ + % float quatern_b; /* 108 + 4 */ + % float quatern_c; /* 112 + 4 */ + % float quatern_d; /* 116 + 4 */ + % float qoffset_x; /* 120 + 4 */ + % float qoffset_y; /* 124 + 4 */ + % float qoffset_z; /* 128 + 4 */ + % float srow_x[4]; /* 132 + 16 */ + % float srow_y[4]; /* 148 + 16 */ + % float srow_z[4]; /* 164 + 16 */ + % char intent_name[16]; /* 180 + 16 */ + % char magic[4]; % int smin; /* 196 + 4 */ + % }; /* total=200 bytes */ + + % descrip = sprintf('%-80s', hist.descrip); % 80 chars from left + % fwrite(fid, descrip(1:80), 'uchar'); + pad = zeros(1, 80-length(hist.descrip)); + hist.descrip = [hist.descrip char(pad)]; + fwrite(fid, hist.descrip(1:80), 'uchar'); + + % aux_file = sprintf('%-24s', hist.aux_file); % 24 chars from left + % fwrite(fid, aux_file(1:24), 'uchar'); + pad = zeros(1, 24-length(hist.aux_file)); + hist.aux_file = [hist.aux_file char(pad)]; + fwrite(fid, hist.aux_file(1:24), 'uchar'); + + fwrite(fid, hist.qform_code, 'int16'); + fwrite(fid, hist.sform_code, 'int16'); + fwrite(fid, hist.quatern_b, 'float32'); + fwrite(fid, hist.quatern_c, 'float32'); + fwrite(fid, hist.quatern_d, 'float32'); + fwrite(fid, hist.qoffset_x, 'float32'); + fwrite(fid, hist.qoffset_y, 'float32'); + fwrite(fid, hist.qoffset_z, 'float32'); + fwrite(fid, hist.srow_x(1:4), 'float32'); + fwrite(fid, hist.srow_y(1:4), 'float32'); + fwrite(fid, hist.srow_z(1:4), 'float32'); + + % intent_name = sprintf('%-16s', hist.intent_name); % 16 chars from left + % fwrite(fid, intent_name(1:16), 'uchar'); + pad = zeros(1, 16-length(hist.intent_name)); + hist.intent_name = [hist.intent_name char(pad)]; + fwrite(fid, hist.intent_name(1:16), 'uchar'); + + % magic = sprintf('%-4s', hist.magic); % 4 chars from left + % fwrite(fid, magic(1:4), 'uchar'); + pad = zeros(1, 4-length(hist.magic)); + hist.magic = [hist.magic char(pad)]; + fwrite(fid, hist.magic(1:4), 'uchar'); + + return; % data_history + diff --git a/matlab/torchsrc/models/Unet.py b/matlab/torchsrc/models/Unet.py index b97369c..039dc95 100644 --- a/matlab/torchsrc/models/Unet.py +++ b/matlab/torchsrc/models/Unet.py @@ -1,330 +1,330 @@ -import numpy as np -import torch -import torch.nn as nn -import torch.nn.functional as F - -# https://github.com/shelhamer/fcn.berkeleyvision.org/blob/master/surgery.py -def get_upsample_filter(size): - """Make a 2D bilinear kernel suitable for upsampling""" - factor = (size + 1) // 2 - if size % 2 == 1: - center = factor - 1 - else: - center = factor - 0.5 - og = np.ogrid[:size, :size] - filter = (1 - abs(og[0] - center) / factor) * \ - (1 - abs(og[1] - center) / factor) - return torch.from_numpy(filter).float() - - -def _score_layer( bottom, name, num_classes): - with tf.variable_scope(name) as scope: - # get number of input channels - in_features = bottom.get_shape()[3].value - #print name,bottom.get_shape().as_list() - shape = [1, 1, in_features, num_classes] - # He initialization Sheme - if name == "score_fr": - num_input = in_features - stddev = (2 / num_input)**0.5 - #elif name == "score_pool4": - # stddev = 0.001 - #elif name == "score_pool3": - # stddev = 0.0001 - else: - stddev = 0.001 - # Apply convolution - w_decay = wd - - weights = _variable_with_weight_decay(shape, stddev, w_decay, - decoder=True) - conv = tf.nn.conv2d(bottom, weights, [1, 1, 1, 1], padding='SAME') - # Apply bias - conv_biases = _bias_variable([num_classes], constant=0.0) - bias = tf.nn.bias_add(conv, conv_biases) - - _activation_summary(bias) - - -class UNetUpBlock(nn.Module): - def __init__(self, in_size, out_size, kernel_size=3, activation=F.relu, space_dropout=False): - super(UNetUpBlock, self).__init__() - self.up = nn.Sequential( - nn.ConvTranspose2d(in_size, out_size, 2, stride=2), - nn.BatchNorm2d(out_size) - ) - self.conv_1 = nn.Sequential( - nn.Conv2d(in_size, out_size, kernel_size, padding=1), - nn.BatchNorm2d(out_size) - ) - self.activation = activation - - def forward(self, x, bridge): - # print("x = %s"%(str(x.size()))) - up = self.up(x) - # print("up = %s"%(str(up.size()))) - # print("bridge = %s"%(str(bridge.size()))) - out = torch.cat([up, bridge], 1) - out = self.activation(self.conv_1(out)) - return out - -class Unet(nn.Module): - - def __init__(self, n_class=21, nodeconv=False): - super(Unet, self).__init__() - self.nodeconv = nodeconv - self.conv1 = nn.Sequential( - # conv1 - nn.Conv2d(3, 64, 3, padding=1), - nn.ReLU(inplace=True), - nn.Conv2d(64, 64, 3, padding=1), - nn.ReLU(inplace=True), - nn.MaxPool2d(2, stride=2, ceil_mode=True), # 1/2 - ) - - self.conv2 = nn.Sequential( - # conv2 - nn.Conv2d(64, 128, 3, padding=1), - nn.ReLU(inplace=True), - nn.Conv2d(128, 128, 3, padding=1), - nn.ReLU(inplace=True), - nn.MaxPool2d(2, stride=2, ceil_mode=True), # 1/4 - ) - - - self.conv3 = nn.Sequential( - # conv3 - nn.Conv2d(128, 256, 3, padding=1), - nn.ReLU(inplace=True), - nn.Conv2d(256, 256, 3, padding=1), - nn.ReLU(inplace=True), - nn.Conv2d(256, 256, 3, padding=1), - nn.ReLU(inplace=True), - nn.MaxPool2d(2, stride=2, ceil_mode=True), # 1/8 - ) - - self.conv4 = nn.Sequential( - # conv4 - nn.Conv2d(256, 512, 3, padding=1), - nn.ReLU(inplace=True), - nn.Conv2d(512, 512, 3, padding=1), - nn.ReLU(inplace=True), - nn.Conv2d(512, 512, 3, padding=1), - nn.ReLU(inplace=True), - nn.MaxPool2d(2, stride=2, ceil_mode=True), # 1/16 - ) - - self.conv5 = nn.Sequential( - # conv5 - nn.Conv2d(512, 512, 3, padding=1), - nn.ReLU(inplace=True), - nn.Conv2d(512, 512, 3, padding=1), - nn.ReLU(inplace=True), - nn.Conv2d(512, 512, 3, padding=1), - nn.ReLU(inplace=True), - nn.MaxPool2d(2, stride=2, ceil_mode=True), # 1/32 - ) - - self.classifier = nn.Sequential( - # fc6 - nn.Conv2d(512, 4096, 7, padding=1), - nn.ReLU(inplace=True), - nn.Dropout2d(), - - # fc7 - nn.Conv2d(4096, 4096, 1, padding=1), - nn.ReLU(inplace=True), - nn.Dropout2d(), - - # score_fr - nn.Conv2d(4096, n_class, 1, padding=1), - ) - - self.maxPool_fc = nn.Sequential( - nn.MaxPool2d(2, stride=2, ceil_mode=True), - ) - - self.classifier_fc = nn.Sequential( - nn.Linear(8*8*512,4096), - nn.ReLU(inplace=True), - nn.Dropout2d(), - - nn.Linear(4096,4096), - nn.ReLU(inplace=True), - nn.Dropout2d(), - - nn.Linear(4096,n_class), - ) - - self.conv_block512_1024 = nn.Sequential( - nn.Conv2d(512, 1024, 3, stride=1, padding=1), - nn.BatchNorm2d(1024) - ) - - self.conv_block512_numclass = nn.Sequential( - nn.Conv2d(512, n_class, 3, stride=1, padding=1), - nn.BatchNorm2d(n_class) - ) - - self.up_blocknumclass_512 = UNetUpBlock(n_class,n_class) - self.up_block1024_512 = UNetUpBlock(1024, 512) - self.up_block512_256 = UNetUpBlock(512, 256) - self.up_block256_128 = UNetUpBlock(256, 128) - self.up_block128_64 = UNetUpBlock(128, 64) - self.up_sample_256_512 = nn.ConvTranspose2d(64, n_class, 2, stride=2) - - - self._initialize_weights() - - def _initialize_weights(self): - for m in self.modules(): - if isinstance(m, nn.Conv2d): - m.weight.data.normal_(0, 0.01) - if m.bias is not None: - m.bias.data.zero_() - if isinstance(m, nn.ConvTranspose2d): - m.weight.data.normal_(0, 0.01) - if m.bias is not None: - m.bias.data.zero_() - - def forward(self, x): - - # print("input size = %s"%(str(x.size()))) - hc1 = self.conv1(x) - # print("conv1 size = %s"%(str(hc1.size()))) - hc2 = self.conv2(hc1) - # print("conv2 size = %s"%(str(hc2.size()))) - hc3 = self.conv3(hc2) - # print("conv3 size = %s"%(str(hc3.size()))) - hc4 = self.conv4(hc3) - # print("conv4 size = %s"%(str(hc4.size()))) - hc5 = self.conv5(hc4) - # print("conv5 size = %s"%(str(hc5.size()))) - - - - lowest = self.conv_block512_1024(hc5) - #lowest = self.conv_block512_numclass(hc5) - #print("lowest size = %s"%(str(lowest.size()))) - up1 = self.up_block1024_512(lowest, hc4) - #up1 = self.up_blocknumclass_512(lowest, hc4) - # print("up1 size = %s"%(str(up1.size()))) - up2 = self.up_block512_256(up1, hc3) - # print("up2 size = %s"%(str(up2.size()))) - up3 = self.up_block256_128(up2, hc2) - # print("up3 size = %s"%(str(up3.size()))) - up4 = self.up_block128_64(up3, hc1) - # print("up4 size = %s"%(str(up4.size()))) - pred = self.up_sample_256_512(up4) - # pred = self.last(up4) - - # print("pred size = %s"%(str(pred.size()))) - - - - - #I tensorflow/core/kernels/logging_ops.cc:79] Shape of input image: [8 512 512 3] -#I tensorflow/core/kernels/logging_ops.cc:79] Shape of pool1[8 256 256 64] -#I tensorflow/core/kernels/logging_ops.cc:79] Shape of pool2[8 128 128 128] -#I tensorflow/core/kernels/logging_ops.cc:79] Shape of pool3[8 64 64 256] -#I tensorflow/core/kernels/logging_ops.cc:79] Shape of pool4[8 32 32 512] -#I tensorflow/core/kernels/logging_ops.cc:79] Shape of pool5[8 16 16 512] -#I tensorflow/core/kernels/logging_ops.cc:79] Shape of fc6[8 16 16 4096] -#I tensorflow/core/kernels/logging_ops.cc:79] Shape of fc7[8 16 16 4096] -#I tensorflow/core/kernels/logging_ops.cc:79] Shape of fc8[8 16 16 3] -#I tensorflow/core/kernels/logging_ops.cc:79] Shape of upscore5[8 32 32 3] -#I tensorflow/core/kernels/logging_ops.cc:79] Shape of upscore4[8 64 64 3] -#I tensorflow/core/kernels/logging_ops.cc:79] Shape of upscore3[8 128 128 3] -#I tensorflow/core/kernels/logging_ops.cc:79] Shape of upscore2[8 256 256 3] -#I tensorflow/core/kernels/logging_ops.cc:79] Shape of upscore1[8 512 512 3] - - return pred - - def copy_params_from_vgg16(self, vgg16, copy_classifier=True, copy_fc8=True, init_upscore=True): - - self.conv1[0].weight.data = vgg16.features[0].weight.data; - self.conv1[0].bias.data = vgg16.features[0].bias.data; - # self.conv1[1].weight.data = vgg16.features[1].weight.data; - # self.conv1[1].bias.data = vgg16.features[1].bias.data; - self.conv1[2].weight.data = vgg16.features[2].weight.data; - self.conv1[2].bias.data = vgg16.features[2].bias.data; - # self.conv1[3].weight.data = vgg16.features[3].weight.data; - # self.conv1[3].bias.data = vgg16.features[3].bias.data; - # self.conv1[4].weight.data = vgg16.features[4].weight.data; - # self.conv1[4].bias.data = vgg16.features[4].bias.data; - - self.conv2[0].weight.data = vgg16.features[5].weight.data; - self.conv2[0].bias.data = vgg16.features[5].bias.data; - # self.conv2[1].weight.data = vgg16.features[6].weight.data; - # self.conv2[1].bias.data = vgg16.features[6].bias.data; - self.conv2[2].weight.data = vgg16.features[7].weight.data; - self.conv2[2].bias.data = vgg16.features[7].bias.data; - # self.conv2[3].weight.data = vgg16.features[8].weight.data; - # self.conv2[3].bias.data = vgg16.features[8].bias.data; - # self.conv2[4].weight.data = vgg16.features[9].weight.data; - # self.conv2[4].bias.data = vgg16.features[9].bias.data; - - self.conv3[0].weight.data = vgg16.features[10].weight.data; - self.conv3[0].bias.data = vgg16.features[10].bias.data; - # self.conv3[1].weight.data = vgg16.features[11].weight.data; - # self.conv3[1].bias.data = vgg16.features[11].bias.data; - self.conv3[2].weight.data = vgg16.features[12].weight.data; - self.conv3[2].bias.data = vgg16.features[12].bias.data; - # self.conv3[3].weight.data = vgg16.features[13].weight.data; - # self.conv3[3].bias.data = vgg16.features[13].bias.data; - self.conv3[4].weight.data = vgg16.features[14].weight.data; - self.conv3[4].bias.data = vgg16.features[14].bias.data; - # self.conv3[5].weight.data = vgg16.features[15].weight.data; - # self.conv3[5].bias.data = vgg16.features[15].bias.data; - # self.conv3[6].weight.data = vgg16.features[16].weight.data; - # self.conv3[6].bias.data = vgg16.features[16].bias.data; - - self.conv4[0].weight.data = vgg16.features[17].weight.data; - self.conv4[0].bias.data = vgg16.features[17].bias.data; - # self.conv4[1].weight.data = vgg16.features[18].weight.data; - # self.conv4[1].bias.data = vgg16.features[18].bias.data; - self.conv4[2].weight.data = vgg16.features[19].weight.data; - self.conv4[2].bias.data = vgg16.features[19].bias.data; - # self.conv4[3].weight.data = vgg16.features[20].weight.data; - # self.conv4[3].bias.data = vgg16.features[20].bias.data; - self.conv4[4].weight.data = vgg16.features[21].weight.data; - self.conv4[4].bias.data = vgg16.features[21].bias.data; - # self.conv4[5].weight.data = vgg16.features[22].weight.data; - # self.conv4[5].bias.data = vgg16.features[22].bias.data; - # self.conv4[6].weight.data = vgg16.features[23].weight.data; - # self.conv4[6].bias.data = vgg16.features[23].bias.data; - - self.conv5[0].weight.data = vgg16.features[24].weight.data; - self.conv5[0].bias.data = vgg16.features[24].bias.data; - # self.conv5[1].weight.data = vgg16.features[25].weight.data; - # self.conv5[1].bias.data = vgg16.features[25].bias.data; - self.conv5[2].weight.data = vgg16.features[26].weight.data; - self.conv5[2].bias.data = vgg16.features[26].bias.data; - # self.conv5[3].weight.data = vgg16.features[27].weight.data; - # self.conv5[3].bias.data = vgg16.features[27].bias.data; - self.conv5[4].weight.data = vgg16.features[28].weight.data; - self.conv5[4].bias.data = vgg16.features[28].bias.data; - # self.conv5[5].weight.data = vgg16.features[29].weight.data; - # self.conv5[5].bias.data = vgg16.features[29].bias.data; - # self.conv5[6].weight.data = vgg16.features[30].weight.data; - # self.conv5[6].bias.data = vgg16.features[30].bias.data; - if copy_classifier: - for i in [0, 3]: - l1 = vgg16.classifier[i] - l2 = self.classifier[i] - l2.weight.data = l1.weight.data.view(l2.weight.size()) - l2.bias.data = l1.bias.data.view(l2.bias.size()) - n_class = self.classifier[6].weight.size()[0] - if copy_fc8: - l1 = vgg16.classifier[6] - l2 = self.classifier[6] - l2.weight.data = l1.weight.data[:n_class, :].view(l2.weight.size()) - l2.bias.data = l1.bias.data[:n_class] - if init_upscore: - # initialize upscore layer - c1, c2, h, w = self.upscore.weight.data.size() - assert c1 == c2 == n_class - assert h == w - weight = get_upsample_filter(h) - self.upscore.weight.data = \ - weight.view(1, 1, h, w).repeat(c1, c2, 1, 1) +import numpy as np +import torch +import torch.nn as nn +import torch.nn.functional as F + +# https://github.com/shelhamer/fcn.berkeleyvision.org/blob/master/surgery.py +def get_upsample_filter(size): + """Make a 2D bilinear kernel suitable for upsampling""" + factor = (size + 1) // 2 + if size % 2 == 1: + center = factor - 1 + else: + center = factor - 0.5 + og = np.ogrid[:size, :size] + filter = (1 - abs(og[0] - center) / factor) * \ + (1 - abs(og[1] - center) / factor) + return torch.from_numpy(filter).float() + + +def _score_layer( bottom, name, num_classes): + with tf.variable_scope(name) as scope: + # get number of input channels + in_features = bottom.get_shape()[3].value + #print name,bottom.get_shape().as_list() + shape = [1, 1, in_features, num_classes] + # He initialization Sheme + if name == "score_fr": + num_input = in_features + stddev = (2 / num_input)**0.5 + #elif name == "score_pool4": + # stddev = 0.001 + #elif name == "score_pool3": + # stddev = 0.0001 + else: + stddev = 0.001 + # Apply convolution + w_decay = wd + + weights = _variable_with_weight_decay(shape, stddev, w_decay, + decoder=True) + conv = tf.nn.conv2d(bottom, weights, [1, 1, 1, 1], padding='SAME') + # Apply bias + conv_biases = _bias_variable([num_classes], constant=0.0) + bias = tf.nn.bias_add(conv, conv_biases) + + _activation_summary(bias) + + +class UNetUpBlock(nn.Module): + def __init__(self, in_size, out_size, kernel_size=3, activation=F.relu, space_dropout=False): + super(UNetUpBlock, self).__init__() + self.up = nn.Sequential( + nn.ConvTranspose2d(in_size, out_size, 2, stride=2), + nn.BatchNorm2d(out_size) + ) + self.conv_1 = nn.Sequential( + nn.Conv2d(in_size, out_size, kernel_size, padding=1), + nn.BatchNorm2d(out_size) + ) + self.activation = activation + + def forward(self, x, bridge): + # print("x = %s"%(str(x.size()))) + up = self.up(x) + # print("up = %s"%(str(up.size()))) + # print("bridge = %s"%(str(bridge.size()))) + out = torch.cat([up, bridge], 1) + out = self.activation(self.conv_1(out)) + return out + +class Unet(nn.Module): + + def __init__(self, n_class=21, nodeconv=False): + super(Unet, self).__init__() + self.nodeconv = nodeconv + self.conv1 = nn.Sequential( + # conv1 + nn.Conv2d(3, 64, 3, padding=1), + nn.ReLU(inplace=True), + nn.Conv2d(64, 64, 3, padding=1), + nn.ReLU(inplace=True), + nn.MaxPool2d(2, stride=2, ceil_mode=True), # 1/2 + ) + + self.conv2 = nn.Sequential( + # conv2 + nn.Conv2d(64, 128, 3, padding=1), + nn.ReLU(inplace=True), + nn.Conv2d(128, 128, 3, padding=1), + nn.ReLU(inplace=True), + nn.MaxPool2d(2, stride=2, ceil_mode=True), # 1/4 + ) + + + self.conv3 = nn.Sequential( + # conv3 + nn.Conv2d(128, 256, 3, padding=1), + nn.ReLU(inplace=True), + nn.Conv2d(256, 256, 3, padding=1), + nn.ReLU(inplace=True), + nn.Conv2d(256, 256, 3, padding=1), + nn.ReLU(inplace=True), + nn.MaxPool2d(2, stride=2, ceil_mode=True), # 1/8 + ) + + self.conv4 = nn.Sequential( + # conv4 + nn.Conv2d(256, 512, 3, padding=1), + nn.ReLU(inplace=True), + nn.Conv2d(512, 512, 3, padding=1), + nn.ReLU(inplace=True), + nn.Conv2d(512, 512, 3, padding=1), + nn.ReLU(inplace=True), + nn.MaxPool2d(2, stride=2, ceil_mode=True), # 1/16 + ) + + self.conv5 = nn.Sequential( + # conv5 + nn.Conv2d(512, 512, 3, padding=1), + nn.ReLU(inplace=True), + nn.Conv2d(512, 512, 3, padding=1), + nn.ReLU(inplace=True), + nn.Conv2d(512, 512, 3, padding=1), + nn.ReLU(inplace=True), + nn.MaxPool2d(2, stride=2, ceil_mode=True), # 1/32 + ) + + self.classifier = nn.Sequential( + # fc6 + nn.Conv2d(512, 4096, 7, padding=1), + nn.ReLU(inplace=True), + nn.Dropout2d(), + + # fc7 + nn.Conv2d(4096, 4096, 1, padding=1), + nn.ReLU(inplace=True), + nn.Dropout2d(), + + # score_fr + nn.Conv2d(4096, n_class, 1, padding=1), + ) + + self.maxPool_fc = nn.Sequential( + nn.MaxPool2d(2, stride=2, ceil_mode=True), + ) + + self.classifier_fc = nn.Sequential( + nn.Linear(8*8*512,4096), + nn.ReLU(inplace=True), + nn.Dropout2d(), + + nn.Linear(4096,4096), + nn.ReLU(inplace=True), + nn.Dropout2d(), + + nn.Linear(4096,n_class), + ) + + self.conv_block512_1024 = nn.Sequential( + nn.Conv2d(512, 1024, 3, stride=1, padding=1), + nn.BatchNorm2d(1024) + ) + + self.conv_block512_numclass = nn.Sequential( + nn.Conv2d(512, n_class, 3, stride=1, padding=1), + nn.BatchNorm2d(n_class) + ) + + self.up_blocknumclass_512 = UNetUpBlock(n_class,n_class) + self.up_block1024_512 = UNetUpBlock(1024, 512) + self.up_block512_256 = UNetUpBlock(512, 256) + self.up_block256_128 = UNetUpBlock(256, 128) + self.up_block128_64 = UNetUpBlock(128, 64) + self.up_sample_256_512 = nn.ConvTranspose2d(64, n_class, 2, stride=2) + + + self._initialize_weights() + + def _initialize_weights(self): + for m in self.modules(): + if isinstance(m, nn.Conv2d): + m.weight.data.normal_(0, 0.01) + if m.bias is not None: + m.bias.data.zero_() + if isinstance(m, nn.ConvTranspose2d): + m.weight.data.normal_(0, 0.01) + if m.bias is not None: + m.bias.data.zero_() + + def forward(self, x): + + # print("input size = %s"%(str(x.size()))) + hc1 = self.conv1(x) + # print("conv1 size = %s"%(str(hc1.size()))) + hc2 = self.conv2(hc1) + # print("conv2 size = %s"%(str(hc2.size()))) + hc3 = self.conv3(hc2) + # print("conv3 size = %s"%(str(hc3.size()))) + hc4 = self.conv4(hc3) + # print("conv4 size = %s"%(str(hc4.size()))) + hc5 = self.conv5(hc4) + # print("conv5 size = %s"%(str(hc5.size()))) + + + + lowest = self.conv_block512_1024(hc5) + #lowest = self.conv_block512_numclass(hc5) + #print("lowest size = %s"%(str(lowest.size()))) + up1 = self.up_block1024_512(lowest, hc4) + #up1 = self.up_blocknumclass_512(lowest, hc4) + # print("up1 size = %s"%(str(up1.size()))) + up2 = self.up_block512_256(up1, hc3) + # print("up2 size = %s"%(str(up2.size()))) + up3 = self.up_block256_128(up2, hc2) + # print("up3 size = %s"%(str(up3.size()))) + up4 = self.up_block128_64(up3, hc1) + # print("up4 size = %s"%(str(up4.size()))) + pred = self.up_sample_256_512(up4) + # pred = self.last(up4) + + # print("pred size = %s"%(str(pred.size()))) + + + + + #I tensorflow/core/kernels/logging_ops.cc:79] Shape of input image: [8 512 512 3] +#I tensorflow/core/kernels/logging_ops.cc:79] Shape of pool1[8 256 256 64] +#I tensorflow/core/kernels/logging_ops.cc:79] Shape of pool2[8 128 128 128] +#I tensorflow/core/kernels/logging_ops.cc:79] Shape of pool3[8 64 64 256] +#I tensorflow/core/kernels/logging_ops.cc:79] Shape of pool4[8 32 32 512] +#I tensorflow/core/kernels/logging_ops.cc:79] Shape of pool5[8 16 16 512] +#I tensorflow/core/kernels/logging_ops.cc:79] Shape of fc6[8 16 16 4096] +#I tensorflow/core/kernels/logging_ops.cc:79] Shape of fc7[8 16 16 4096] +#I tensorflow/core/kernels/logging_ops.cc:79] Shape of fc8[8 16 16 3] +#I tensorflow/core/kernels/logging_ops.cc:79] Shape of upscore5[8 32 32 3] +#I tensorflow/core/kernels/logging_ops.cc:79] Shape of upscore4[8 64 64 3] +#I tensorflow/core/kernels/logging_ops.cc:79] Shape of upscore3[8 128 128 3] +#I tensorflow/core/kernels/logging_ops.cc:79] Shape of upscore2[8 256 256 3] +#I tensorflow/core/kernels/logging_ops.cc:79] Shape of upscore1[8 512 512 3] + + return pred + + def copy_params_from_vgg16(self, vgg16, copy_classifier=True, copy_fc8=True, init_upscore=True): + + self.conv1[0].weight.data = vgg16.features[0].weight.data; + self.conv1[0].bias.data = vgg16.features[0].bias.data; + # self.conv1[1].weight.data = vgg16.features[1].weight.data; + # self.conv1[1].bias.data = vgg16.features[1].bias.data; + self.conv1[2].weight.data = vgg16.features[2].weight.data; + self.conv1[2].bias.data = vgg16.features[2].bias.data; + # self.conv1[3].weight.data = vgg16.features[3].weight.data; + # self.conv1[3].bias.data = vgg16.features[3].bias.data; + # self.conv1[4].weight.data = vgg16.features[4].weight.data; + # self.conv1[4].bias.data = vgg16.features[4].bias.data; + + self.conv2[0].weight.data = vgg16.features[5].weight.data; + self.conv2[0].bias.data = vgg16.features[5].bias.data; + # self.conv2[1].weight.data = vgg16.features[6].weight.data; + # self.conv2[1].bias.data = vgg16.features[6].bias.data; + self.conv2[2].weight.data = vgg16.features[7].weight.data; + self.conv2[2].bias.data = vgg16.features[7].bias.data; + # self.conv2[3].weight.data = vgg16.features[8].weight.data; + # self.conv2[3].bias.data = vgg16.features[8].bias.data; + # self.conv2[4].weight.data = vgg16.features[9].weight.data; + # self.conv2[4].bias.data = vgg16.features[9].bias.data; + + self.conv3[0].weight.data = vgg16.features[10].weight.data; + self.conv3[0].bias.data = vgg16.features[10].bias.data; + # self.conv3[1].weight.data = vgg16.features[11].weight.data; + # self.conv3[1].bias.data = vgg16.features[11].bias.data; + self.conv3[2].weight.data = vgg16.features[12].weight.data; + self.conv3[2].bias.data = vgg16.features[12].bias.data; + # self.conv3[3].weight.data = vgg16.features[13].weight.data; + # self.conv3[3].bias.data = vgg16.features[13].bias.data; + self.conv3[4].weight.data = vgg16.features[14].weight.data; + self.conv3[4].bias.data = vgg16.features[14].bias.data; + # self.conv3[5].weight.data = vgg16.features[15].weight.data; + # self.conv3[5].bias.data = vgg16.features[15].bias.data; + # self.conv3[6].weight.data = vgg16.features[16].weight.data; + # self.conv3[6].bias.data = vgg16.features[16].bias.data; + + self.conv4[0].weight.data = vgg16.features[17].weight.data; + self.conv4[0].bias.data = vgg16.features[17].bias.data; + # self.conv4[1].weight.data = vgg16.features[18].weight.data; + # self.conv4[1].bias.data = vgg16.features[18].bias.data; + self.conv4[2].weight.data = vgg16.features[19].weight.data; + self.conv4[2].bias.data = vgg16.features[19].bias.data; + # self.conv4[3].weight.data = vgg16.features[20].weight.data; + # self.conv4[3].bias.data = vgg16.features[20].bias.data; + self.conv4[4].weight.data = vgg16.features[21].weight.data; + self.conv4[4].bias.data = vgg16.features[21].bias.data; + # self.conv4[5].weight.data = vgg16.features[22].weight.data; + # self.conv4[5].bias.data = vgg16.features[22].bias.data; + # self.conv4[6].weight.data = vgg16.features[23].weight.data; + # self.conv4[6].bias.data = vgg16.features[23].bias.data; + + self.conv5[0].weight.data = vgg16.features[24].weight.data; + self.conv5[0].bias.data = vgg16.features[24].bias.data; + # self.conv5[1].weight.data = vgg16.features[25].weight.data; + # self.conv5[1].bias.data = vgg16.features[25].bias.data; + self.conv5[2].weight.data = vgg16.features[26].weight.data; + self.conv5[2].bias.data = vgg16.features[26].bias.data; + # self.conv5[3].weight.data = vgg16.features[27].weight.data; + # self.conv5[3].bias.data = vgg16.features[27].bias.data; + self.conv5[4].weight.data = vgg16.features[28].weight.data; + self.conv5[4].bias.data = vgg16.features[28].bias.data; + # self.conv5[5].weight.data = vgg16.features[29].weight.data; + # self.conv5[5].bias.data = vgg16.features[29].bias.data; + # self.conv5[6].weight.data = vgg16.features[30].weight.data; + # self.conv5[6].bias.data = vgg16.features[30].bias.data; + if copy_classifier: + for i in [0, 3]: + l1 = vgg16.classifier[i] + l2 = self.classifier[i] + l2.weight.data = l1.weight.data.view(l2.weight.size()) + l2.bias.data = l1.bias.data.view(l2.bias.size()) + n_class = self.classifier[6].weight.size()[0] + if copy_fc8: + l1 = vgg16.classifier[6] + l2 = self.classifier[6] + l2.weight.data = l1.weight.data[:n_class, :].view(l2.weight.size()) + l2.bias.data = l1.bias.data[:n_class] + if init_upscore: + # initialize upscore layer + c1, c2, h, w = self.upscore.weight.data.size() + assert c1 == c2 == n_class + assert h == w + weight = get_upsample_filter(h) + self.upscore.weight.data = \ + weight.view(1, 1, h, w).repeat(c1, c2, 1, 1) diff --git a/matlab/torchsrc/models/Unet_online.py b/matlab/torchsrc/models/Unet_online.py index 9935a9e..d38ab47 100644 --- a/matlab/torchsrc/models/Unet_online.py +++ b/matlab/torchsrc/models/Unet_online.py @@ -1,94 +1,94 @@ -import numpy as np -import torch -import torch.nn as nn -import torch.nn.functional as F - -# from https://discuss.pytorch.org/t/unet-implementation/426 -class UNetConvBlock(nn.Module): - def __init__(self, in_size, out_size, kernel_size=3, activation=F.relu): - super(UNetConvBlock, self).__init__() - self.conv = nn.Conv2d(in_size, out_size, kernel_size) - self.conv2 = nn.Conv2d(out_size, out_size, kernel_size) - self.activation = activation - - def forward(self, x): - out = self.activation(self.conv(x)) - out = self.activation(self.conv2(out)) - - return out - - -class UNetUpBlock(nn.Module): - def __init__(self, in_size, out_size, kernel_size=3, activation=F.relu, space_dropout=False): - super(UNetUpBlock, self).__init__() - self.up = nn.ConvTranspose2d(in_size, out_size, 2, stride=2) - self.conv = nn.Conv2d(in_size, out_size, kernel_size) - self.conv2 = nn.Conv2d(out_size, out_size, kernel_size) - self.activation = activation - - def center_crop(self, layer, target_size): - batch_size, n_channels, layer_width, layer_height = layer.size() - xy1 = (layer_width - target_size) // 2 - return layer[:, :, xy1:(xy1 + target_size), xy1:(xy1 + target_size)] - - def forward(self, x, bridge): - up = self.up(x) - crop1 = self.center_crop(bridge, up.size()[2]) - out = torch.cat([up, crop1], 1) - out = self.activation(self.conv(out)) - out = self.activation(self.conv2(out)) - - return out - - -class Unet_online(nn.Module): - def __init__(self, imsize): - super(Unet_online, self).__init__() - self.imsize = imsize - - self.activation = F.relu - - self.pool1 = nn.MaxPool2d(2) - self.pool2 = nn.MaxPool2d(2) - self.pool3 = nn.MaxPool2d(2) - self.pool4 = nn.MaxPool2d(2) - - self.conv_block1_64 = UNetConvBlock(3, 64) #yuankai change 1 to 3 - self.conv_block64_128 = UNetConvBlock(64, 128) - self.conv_block128_256 = UNetConvBlock(128, 256) - self.conv_block256_512 = UNetConvBlock(256, 512) - self.conv_block512_1024 = UNetConvBlock(512, 1024) - - self.up_block1024_512 = UNetUpBlock(1024, 512) - self.up_block512_256 = UNetUpBlock(512, 256) - self.up_block256_128 = UNetUpBlock(256, 128) - self.up_block128_64 = UNetUpBlock(128, 64) - - self.last = nn.Conv2d(64, 2, 1) - - - def forward(self, x): - block1 = self.conv_block1_64(x) - pool1 = self.pool1(block1) - - block2 = self.conv_block64_128(pool1) - pool2 = self.pool2(block2) - - block3 = self.conv_block128_256(pool2) - pool3 = self.pool3(block3) - - block4 = self.conv_block256_512(pool3) - pool4 = self.pool4(block4) - - block5 = self.conv_block512_1024(pool4) - - up1 = self.up_block1024_512(block5, block4) - - up2 = self.up_block512_256(up1, block3) - - up3 = self.up_block256_128(up2, block2) - - up4 = self.up_block128_64(up3, block1) - - # return F.log_softmax(self.last(up4)) +import numpy as np +import torch +import torch.nn as nn +import torch.nn.functional as F + +# from https://discuss.pytorch.org/t/unet-implementation/426 +class UNetConvBlock(nn.Module): + def __init__(self, in_size, out_size, kernel_size=3, activation=F.relu): + super(UNetConvBlock, self).__init__() + self.conv = nn.Conv2d(in_size, out_size, kernel_size) + self.conv2 = nn.Conv2d(out_size, out_size, kernel_size) + self.activation = activation + + def forward(self, x): + out = self.activation(self.conv(x)) + out = self.activation(self.conv2(out)) + + return out + + +class UNetUpBlock(nn.Module): + def __init__(self, in_size, out_size, kernel_size=3, activation=F.relu, space_dropout=False): + super(UNetUpBlock, self).__init__() + self.up = nn.ConvTranspose2d(in_size, out_size, 2, stride=2) + self.conv = nn.Conv2d(in_size, out_size, kernel_size) + self.conv2 = nn.Conv2d(out_size, out_size, kernel_size) + self.activation = activation + + def center_crop(self, layer, target_size): + batch_size, n_channels, layer_width, layer_height = layer.size() + xy1 = (layer_width - target_size) // 2 + return layer[:, :, xy1:(xy1 + target_size), xy1:(xy1 + target_size)] + + def forward(self, x, bridge): + up = self.up(x) + crop1 = self.center_crop(bridge, up.size()[2]) + out = torch.cat([up, crop1], 1) + out = self.activation(self.conv(out)) + out = self.activation(self.conv2(out)) + + return out + + +class Unet_online(nn.Module): + def __init__(self, imsize): + super(Unet_online, self).__init__() + self.imsize = imsize + + self.activation = F.relu + + self.pool1 = nn.MaxPool2d(2) + self.pool2 = nn.MaxPool2d(2) + self.pool3 = nn.MaxPool2d(2) + self.pool4 = nn.MaxPool2d(2) + + self.conv_block1_64 = UNetConvBlock(3, 64) #yuankai change 1 to 3 + self.conv_block64_128 = UNetConvBlock(64, 128) + self.conv_block128_256 = UNetConvBlock(128, 256) + self.conv_block256_512 = UNetConvBlock(256, 512) + self.conv_block512_1024 = UNetConvBlock(512, 1024) + + self.up_block1024_512 = UNetUpBlock(1024, 512) + self.up_block512_256 = UNetUpBlock(512, 256) + self.up_block256_128 = UNetUpBlock(256, 128) + self.up_block128_64 = UNetUpBlock(128, 64) + + self.last = nn.Conv2d(64, 2, 1) + + + def forward(self, x): + block1 = self.conv_block1_64(x) + pool1 = self.pool1(block1) + + block2 = self.conv_block64_128(pool1) + pool2 = self.pool2(block2) + + block3 = self.conv_block128_256(pool2) + pool3 = self.pool3(block3) + + block4 = self.conv_block256_512(pool3) + pool4 = self.pool4(block4) + + block5 = self.conv_block512_1024(pool4) + + up1 = self.up_block1024_512(block5, block4) + + up2 = self.up_block512_256(up1, block3) + + up3 = self.up_block256_128(up2, block2) + + up4 = self.up_block128_64(up3, block1) + + # return F.log_softmax(self.last(up4)) return up4 \ No newline at end of file diff --git a/matlab/torchsrc/models/fcn32s_BN.py b/matlab/torchsrc/models/fcn32s_BN.py index 903bd4a..dd61567 100644 --- a/matlab/torchsrc/models/fcn32s_BN.py +++ b/matlab/torchsrc/models/fcn32s_BN.py @@ -1,273 +1,273 @@ -import numpy as np -import torch -import torch.nn as nn -import torch.nn.functional as F - -# https://github.com/shelhamer/fcn.berkeleyvision.org/blob/master/surgery.py -def get_upsample_filter(size): - """Make a 2D bilinear kernel suitable for upsampling""" - factor = (size + 1) // 2 - if size % 2 == 1: - center = factor - 1 - else: - center = factor - 0.5 - og = np.ogrid[:size, :size] - filter = (1 - abs(og[0] - center) / factor) * \ - (1 - abs(og[1] - center) / factor) - return torch.from_numpy(filter).float() - - -class FCN32s_BN(nn.Module): - - def __init__(self, n_class=21, nodeconv=False): - super(FCN32s_BN, self).__init__() - self.nodeconv = nodeconv - self.conv1 = nn.Sequential( - # conv1 - nn.Conv2d(3, 64, 3, padding=1), - nn.BatchNorm2d(64), - nn.ReLU(inplace=True), - nn.Conv2d(64, 64, 3, padding=1), - nn.BatchNorm2d(64), - nn.ReLU(inplace=True), - nn.MaxPool2d(2, stride=2, ceil_mode=True), # 1/2 - ) - - self.conv2 = nn.Sequential( - # conv2 - nn.Conv2d(64, 128, 3, padding=1), - nn.BatchNorm2d(128), - nn.ReLU(inplace=True), - nn.Conv2d(128, 128, 3, padding=1), - nn.BatchNorm2d(128), - nn.ReLU(inplace=True), - nn.MaxPool2d(2, stride=2, ceil_mode=True), # 1/4 - ) - - - self.conv3 = nn.Sequential( - # conv3 - nn.Conv2d(128, 256, 3, padding=1), - nn.BatchNorm2d(256), - nn.ReLU(inplace=True), - nn.Conv2d(256, 256, 3, padding=1), - nn.BatchNorm2d(256), - nn.ReLU(inplace=True), - nn.Conv2d(256, 256, 3, padding=1), - nn.BatchNorm2d(256), - nn.ReLU(inplace=True), - nn.MaxPool2d(2, stride=2, ceil_mode=True), # 1/8 - ) - - self.conv4 = nn.Sequential( - # conv4 - nn.Conv2d(256, 512, 3, padding=1), - nn.BatchNorm2d(512), - nn.ReLU(inplace=True), - nn.Conv2d(512, 512, 3, padding=1), - nn.BatchNorm2d(512), - nn.ReLU(inplace=True), - nn.Conv2d(512, 512, 3, padding=1), - nn.BatchNorm2d(512), - nn.ReLU(inplace=True), - nn.MaxPool2d(2, stride=2, ceil_mode=True), # 1/16 - ) - - self.conv5 = nn.Sequential( - # conv5 - nn.Conv2d(512, 512, 3, padding=1), - nn.BatchNorm2d(512), - nn.ReLU(inplace=True), - nn.Conv2d(512, 512, 3, padding=1), - nn.BatchNorm2d(512), - nn.ReLU(inplace=True), - nn.Conv2d(512, 512, 3, padding=1), - nn.BatchNorm2d(512), - nn.ReLU(inplace=True), - nn.MaxPool2d(2, stride=2, ceil_mode=True), # 1/32 - ) - - self.classifier = nn.Sequential( - # fc6 - nn.Conv2d(512, 1024, 7, padding=1), - nn.BatchNorm2d(1024), - nn.ReLU(inplace=True), - nn.Dropout2d(), - - # fc7 - nn.Conv2d(1024, 1024, 1, padding=1), - nn.BatchNorm2d(1024), - nn.ReLU(inplace=True), - nn.Dropout2d(), - - # score_fr - nn.Conv2d(1024, n_class, 1, padding=1), - ) - - self.maxPool_fc = nn.Sequential( - nn.MaxPool2d(2, stride=2, ceil_mode=True), - nn.BatchNorm2d(512), - ) - - - self.upscore = nn.Sequential( - nn.ConvTranspose2d(n_class,n_class,4,stride=2,padding=1,output_padding=0,bias=True), - nn.BatchNorm2d(n_class), - ) - - self.upscore4 = nn.Sequential( - nn.ConvTranspose2d(n_class,n_class,4,stride=2,padding=1,output_padding=0,bias=True), - nn.BatchNorm2d(n_class), - ) - - self.upscore3 = nn.Sequential( - nn.ConvTranspose2d(n_class,n_class,4,stride=2,padding=1,output_padding=0,bias=True), - nn.BatchNorm2d(n_class), - ) - - self.upscore2 = nn.Sequential( - nn.ConvTranspose2d(n_class,n_class,4,stride=2,padding=1,output_padding=0,bias=True), - nn.BatchNorm2d(n_class), - ) - - self.upscore1 = nn.Sequential( - nn.ConvTranspose2d(n_class,n_class,4,stride=2,padding=1,output_padding=0,bias=True), - nn.BatchNorm2d(n_class), - ) - - self.score4 = nn.Sequential( - # torch.nn.Conv2d(in_channels, out_channels, kernel_size, - # stride=1, padding=0, dilation=1, - # groups=1, bias=True) - # batch x 1 x 28 x 28 -> batch x 512 - nn.Conv2d(512, n_class, 1, stride=1, padding=0), - nn.BatchNorm2d(n_class), - ) - - - self.score3 = nn.Sequential( - nn.Conv2d(256, n_class, 1, stride=1, padding=0), - nn.BatchNorm2d(n_class), - ) - - self.score2 = nn.Sequential( - nn.Conv2d(128, n_class, 1, stride=1, padding=0), - nn.BatchNorm2d(n_class), - ) - - self.score1 = nn.Sequential( - nn.Conv2d(64, n_class, 1, stride=1, padding=0), - nn.BatchNorm2d(n_class), - ) - - - - self._initialize_weights() - - def _initialize_weights(self): - for m in self.modules(): - if isinstance(m, nn.Conv2d): - m.weight.data.normal_(0, 0.01) - if m.bias is not None: - m.bias.data.zero_() - if isinstance(m, nn.ConvTranspose2d): - m.weight.data.normal_(0, 0.01) - if m.bias is not None: - m.bias.data.zero_() - - def forward(self, x): - - #print("input size = %s"%(str(x.size()))) - hc1 = self.conv1(x) - #print("conv1 size = %s"%(str(hc1.size()))) - hc2 = self.conv2(hc1) - #print("conv2 size = %s"%(str(hc2.size()))) - hc3 = self.conv3(hc2) - #print("conv3 size = %s"%(str(hc3.size()))) - hc4 = self.conv4(hc3) - #print("conv4 size = %s"%(str(hc4.size()))) - hc5 = self.conv5(hc4) - #print("conv5 size = %s"%(str(hc5.size()))) - hc5_f = self.maxPool_fc(hc5) - hc5_f = hc5_f.view(-1,8*8*512) - - ha = self.classifier(hc5) - # #print("classifer size = %s"%(str(ha.size()))) - - hs4 = self.score4(hc4) - hd4 = self.upscore4(ha) - hf4 = torch.add(hs4, hd4) - # #print("deconv4 size = %s"%(str(hf4.size()))) - - hs3 = self.score3(hc3) - hd3 = self.upscore3(hf4) - hf3 = torch.add(hs3, hd3) - # #print("deconv3 size = %s"%(str(hf3.size()))) - - hs2 = self.score2(hc2) - hd2 = self.upscore2(hf3) - hf2 = torch.add(hs2, hd2) - # #print("deconv2 size = %s"%(str(hf2.size()))) - - hs1 = self.score1(hc1) - hd1 = self.upscore1(hf2) - hf1 = torch.add(hs1, hd1) - # #print("deconv1 size = %s"%(str(hf1.size()))) - - h = self.upscore(hf1) - # #print("output size = %s"%(str(h.size()))) - return h - - def copy_params_from_vgg16(self, vgg16, copy_classifier=True, copy_fc8=True, init_upscore=True): - - self.conv1[0].weight.data = vgg16.features[0].weight.data; - self.conv1[0].bias.data = vgg16.features[0].bias.data; - self.conv1[3].weight.data = vgg16.features[2].weight.data; - self.conv1[3].bias.data = vgg16.features[2].bias.data; - - self.conv2[0].weight.data = vgg16.features[5].weight.data; - self.conv2[0].bias.data = vgg16.features[5].bias.data; - self.conv2[3].weight.data = vgg16.features[7].weight.data; - self.conv2[3].bias.data = vgg16.features[7].bias.data; - - self.conv3[0].weight.data = vgg16.features[10].weight.data; - self.conv3[0].bias.data = vgg16.features[10].bias.data; - self.conv3[3].weight.data = vgg16.features[12].weight.data; - self.conv3[3].bias.data = vgg16.features[12].bias.data; - self.conv3[6].weight.data = vgg16.features[14].weight.data; - self.conv3[6].bias.data = vgg16.features[14].bias.data; - - self.conv4[0].weight.data = vgg16.features[17].weight.data; - self.conv4[0].bias.data = vgg16.features[17].bias.data; - self.conv4[3].weight.data = vgg16.features[19].weight.data; - self.conv4[3].bias.data = vgg16.features[19].bias.data; - self.conv4[6].weight.data = vgg16.features[21].weight.data; - self.conv4[6].bias.data = vgg16.features[21].bias.data; - - self.conv5[0].weight.data = vgg16.features[24].weight.data; - self.conv5[0].bias.data = vgg16.features[24].bias.data; - self.conv5[3].weight.data = vgg16.features[26].weight.data; - self.conv5[3].bias.data = vgg16.features[26].bias.data; - self.conv5[6].weight.data = vgg16.features[28].weight.data; - self.conv5[6].bias.data = vgg16.features[28].bias.data; - - if copy_classifier: - for i in [0, 3]: - l1 = vgg16.classifier[i] - l2 = self.classifier[i] - l2.weight.data = l1.weight.data.view(l2.weight.size()) - l2.bias.data = l1.bias.data.view(l2.bias.size()) - n_class = self.classifier[6].weight.size()[0] - if copy_fc8: - l1 = vgg16.classifier[6] - l2 = self.classifier[6] - l2.weight.data = l1.weight.data[:n_class, :].view(l2.weight.size()) - l2.bias.data = l1.bias.data[:n_class] - if init_upscore: - # initialize upscore layer - c1, c2, h, w = self.upscore.weight.data.size() - assert c1 == c2 == n_class - assert h == w - weight = get_upsample_filter(h) - self.upscore.weight.data = \ - weight.view(1, 1, h, w).repeat(c1, c2, 1, 1) +import numpy as np +import torch +import torch.nn as nn +import torch.nn.functional as F + +# https://github.com/shelhamer/fcn.berkeleyvision.org/blob/master/surgery.py +def get_upsample_filter(size): + """Make a 2D bilinear kernel suitable for upsampling""" + factor = (size + 1) // 2 + if size % 2 == 1: + center = factor - 1 + else: + center = factor - 0.5 + og = np.ogrid[:size, :size] + filter = (1 - abs(og[0] - center) / factor) * \ + (1 - abs(og[1] - center) / factor) + return torch.from_numpy(filter).float() + + +class FCN32s_BN(nn.Module): + + def __init__(self, n_class=21, nodeconv=False): + super(FCN32s_BN, self).__init__() + self.nodeconv = nodeconv + self.conv1 = nn.Sequential( + # conv1 + nn.Conv2d(3, 64, 3, padding=1), + nn.BatchNorm2d(64), + nn.ReLU(inplace=True), + nn.Conv2d(64, 64, 3, padding=1), + nn.BatchNorm2d(64), + nn.ReLU(inplace=True), + nn.MaxPool2d(2, stride=2, ceil_mode=True), # 1/2 + ) + + self.conv2 = nn.Sequential( + # conv2 + nn.Conv2d(64, 128, 3, padding=1), + nn.BatchNorm2d(128), + nn.ReLU(inplace=True), + nn.Conv2d(128, 128, 3, padding=1), + nn.BatchNorm2d(128), + nn.ReLU(inplace=True), + nn.MaxPool2d(2, stride=2, ceil_mode=True), # 1/4 + ) + + + self.conv3 = nn.Sequential( + # conv3 + nn.Conv2d(128, 256, 3, padding=1), + nn.BatchNorm2d(256), + nn.ReLU(inplace=True), + nn.Conv2d(256, 256, 3, padding=1), + nn.BatchNorm2d(256), + nn.ReLU(inplace=True), + nn.Conv2d(256, 256, 3, padding=1), + nn.BatchNorm2d(256), + nn.ReLU(inplace=True), + nn.MaxPool2d(2, stride=2, ceil_mode=True), # 1/8 + ) + + self.conv4 = nn.Sequential( + # conv4 + nn.Conv2d(256, 512, 3, padding=1), + nn.BatchNorm2d(512), + nn.ReLU(inplace=True), + nn.Conv2d(512, 512, 3, padding=1), + nn.BatchNorm2d(512), + nn.ReLU(inplace=True), + nn.Conv2d(512, 512, 3, padding=1), + nn.BatchNorm2d(512), + nn.ReLU(inplace=True), + nn.MaxPool2d(2, stride=2, ceil_mode=True), # 1/16 + ) + + self.conv5 = nn.Sequential( + # conv5 + nn.Conv2d(512, 512, 3, padding=1), + nn.BatchNorm2d(512), + nn.ReLU(inplace=True), + nn.Conv2d(512, 512, 3, padding=1), + nn.BatchNorm2d(512), + nn.ReLU(inplace=True), + nn.Conv2d(512, 512, 3, padding=1), + nn.BatchNorm2d(512), + nn.ReLU(inplace=True), + nn.MaxPool2d(2, stride=2, ceil_mode=True), # 1/32 + ) + + self.classifier = nn.Sequential( + # fc6 + nn.Conv2d(512, 1024, 7, padding=1), + nn.BatchNorm2d(1024), + nn.ReLU(inplace=True), + nn.Dropout2d(), + + # fc7 + nn.Conv2d(1024, 1024, 1, padding=1), + nn.BatchNorm2d(1024), + nn.ReLU(inplace=True), + nn.Dropout2d(), + + # score_fr + nn.Conv2d(1024, n_class, 1, padding=1), + ) + + self.maxPool_fc = nn.Sequential( + nn.MaxPool2d(2, stride=2, ceil_mode=True), + nn.BatchNorm2d(512), + ) + + + self.upscore = nn.Sequential( + nn.ConvTranspose2d(n_class,n_class,4,stride=2,padding=1,output_padding=0,bias=True), + nn.BatchNorm2d(n_class), + ) + + self.upscore4 = nn.Sequential( + nn.ConvTranspose2d(n_class,n_class,4,stride=2,padding=1,output_padding=0,bias=True), + nn.BatchNorm2d(n_class), + ) + + self.upscore3 = nn.Sequential( + nn.ConvTranspose2d(n_class,n_class,4,stride=2,padding=1,output_padding=0,bias=True), + nn.BatchNorm2d(n_class), + ) + + self.upscore2 = nn.Sequential( + nn.ConvTranspose2d(n_class,n_class,4,stride=2,padding=1,output_padding=0,bias=True), + nn.BatchNorm2d(n_class), + ) + + self.upscore1 = nn.Sequential( + nn.ConvTranspose2d(n_class,n_class,4,stride=2,padding=1,output_padding=0,bias=True), + nn.BatchNorm2d(n_class), + ) + + self.score4 = nn.Sequential( + # torch.nn.Conv2d(in_channels, out_channels, kernel_size, + # stride=1, padding=0, dilation=1, + # groups=1, bias=True) + # batch x 1 x 28 x 28 -> batch x 512 + nn.Conv2d(512, n_class, 1, stride=1, padding=0), + nn.BatchNorm2d(n_class), + ) + + + self.score3 = nn.Sequential( + nn.Conv2d(256, n_class, 1, stride=1, padding=0), + nn.BatchNorm2d(n_class), + ) + + self.score2 = nn.Sequential( + nn.Conv2d(128, n_class, 1, stride=1, padding=0), + nn.BatchNorm2d(n_class), + ) + + self.score1 = nn.Sequential( + nn.Conv2d(64, n_class, 1, stride=1, padding=0), + nn.BatchNorm2d(n_class), + ) + + + + self._initialize_weights() + + def _initialize_weights(self): + for m in self.modules(): + if isinstance(m, nn.Conv2d): + m.weight.data.normal_(0, 0.01) + if m.bias is not None: + m.bias.data.zero_() + if isinstance(m, nn.ConvTranspose2d): + m.weight.data.normal_(0, 0.01) + if m.bias is not None: + m.bias.data.zero_() + + def forward(self, x): + + #print("input size = %s"%(str(x.size()))) + hc1 = self.conv1(x) + #print("conv1 size = %s"%(str(hc1.size()))) + hc2 = self.conv2(hc1) + #print("conv2 size = %s"%(str(hc2.size()))) + hc3 = self.conv3(hc2) + #print("conv3 size = %s"%(str(hc3.size()))) + hc4 = self.conv4(hc3) + #print("conv4 size = %s"%(str(hc4.size()))) + hc5 = self.conv5(hc4) + #print("conv5 size = %s"%(str(hc5.size()))) + hc5_f = self.maxPool_fc(hc5) + hc5_f = hc5_f.view(-1,8*8*512) + + ha = self.classifier(hc5) + # #print("classifer size = %s"%(str(ha.size()))) + + hs4 = self.score4(hc4) + hd4 = self.upscore4(ha) + hf4 = torch.add(hs4, hd4) + # #print("deconv4 size = %s"%(str(hf4.size()))) + + hs3 = self.score3(hc3) + hd3 = self.upscore3(hf4) + hf3 = torch.add(hs3, hd3) + # #print("deconv3 size = %s"%(str(hf3.size()))) + + hs2 = self.score2(hc2) + hd2 = self.upscore2(hf3) + hf2 = torch.add(hs2, hd2) + # #print("deconv2 size = %s"%(str(hf2.size()))) + + hs1 = self.score1(hc1) + hd1 = self.upscore1(hf2) + hf1 = torch.add(hs1, hd1) + # #print("deconv1 size = %s"%(str(hf1.size()))) + + h = self.upscore(hf1) + # #print("output size = %s"%(str(h.size()))) + return h + + def copy_params_from_vgg16(self, vgg16, copy_classifier=True, copy_fc8=True, init_upscore=True): + + self.conv1[0].weight.data = vgg16.features[0].weight.data; + self.conv1[0].bias.data = vgg16.features[0].bias.data; + self.conv1[3].weight.data = vgg16.features[2].weight.data; + self.conv1[3].bias.data = vgg16.features[2].bias.data; + + self.conv2[0].weight.data = vgg16.features[5].weight.data; + self.conv2[0].bias.data = vgg16.features[5].bias.data; + self.conv2[3].weight.data = vgg16.features[7].weight.data; + self.conv2[3].bias.data = vgg16.features[7].bias.data; + + self.conv3[0].weight.data = vgg16.features[10].weight.data; + self.conv3[0].bias.data = vgg16.features[10].bias.data; + self.conv3[3].weight.data = vgg16.features[12].weight.data; + self.conv3[3].bias.data = vgg16.features[12].bias.data; + self.conv3[6].weight.data = vgg16.features[14].weight.data; + self.conv3[6].bias.data = vgg16.features[14].bias.data; + + self.conv4[0].weight.data = vgg16.features[17].weight.data; + self.conv4[0].bias.data = vgg16.features[17].bias.data; + self.conv4[3].weight.data = vgg16.features[19].weight.data; + self.conv4[3].bias.data = vgg16.features[19].bias.data; + self.conv4[6].weight.data = vgg16.features[21].weight.data; + self.conv4[6].bias.data = vgg16.features[21].bias.data; + + self.conv5[0].weight.data = vgg16.features[24].weight.data; + self.conv5[0].bias.data = vgg16.features[24].bias.data; + self.conv5[3].weight.data = vgg16.features[26].weight.data; + self.conv5[3].bias.data = vgg16.features[26].bias.data; + self.conv5[6].weight.data = vgg16.features[28].weight.data; + self.conv5[6].bias.data = vgg16.features[28].bias.data; + + if copy_classifier: + for i in [0, 3]: + l1 = vgg16.classifier[i] + l2 = self.classifier[i] + l2.weight.data = l1.weight.data.view(l2.weight.size()) + l2.bias.data = l1.bias.data.view(l2.bias.size()) + n_class = self.classifier[6].weight.size()[0] + if copy_fc8: + l1 = vgg16.classifier[6] + l2 = self.classifier[6] + l2.weight.data = l1.weight.data[:n_class, :].view(l2.weight.size()) + l2.bias.data = l1.bias.data[:n_class] + if init_upscore: + # initialize upscore layer + c1, c2, h, w = self.upscore.weight.data.size() + assert c1 == c2 == n_class + assert h == w + weight = get_upsample_filter(h) + self.upscore.weight.data = \ + weight.view(1, 1, h, w).repeat(c1, c2, 1, 1) From e07d537eba20599c646d130d2956eef93d059401 Mon Sep 17 00:00:00 2001 From: heagenb03 Date: Thu, 22 Jan 2026 15:42:24 -0600 Subject: [PATCH 2/2] Add torch.no_grad() to methods with unneccessary gradient calc. - Reduces 50GB of peak memory usage down to ~19GB (64%) --- python/torchsrc/trainer.py | 78 +++++++++++++++++++------------------- 1 file changed, 38 insertions(+), 40 deletions(-) diff --git a/python/torchsrc/trainer.py b/python/torchsrc/trainer.py index 70421d6..b72339e 100644 --- a/python/torchsrc/trainer.py +++ b/python/torchsrc/trainer.py @@ -56,11 +56,12 @@ def weighted_center(input,threshold=0.75): def save_images(results_epoch_dir,data,sub_name,cate_name,pred_lmk,target=None): - saveOneImg(data[0, 0, :, :].data.cpu().numpy(), results_epoch_dir, cate_name,sub_name, "_trueGray") - for i in range(pred_lmk.size()[1]): - saveOneImg(pred_lmk[0, i, :, :].data.cpu().numpy(), results_epoch_dir, cate_name,sub_name, "_pred%d" % (i)) - if not (target is None): - saveOneImg(target[0, i, :, :].data.cpu().numpy(), results_epoch_dir, cate_name,sub_name, "_true%d" % (i)) + with torch.no_grad(): + saveOneImg(data[0, 0, :, :].data.cpu().numpy(), results_epoch_dir, cate_name,sub_name, "_trueGray") + for i in range(pred_lmk.size()[1]): + saveOneImg(pred_lmk[0, i, :, :].data.cpu().numpy(), results_epoch_dir, cate_name,sub_name, "_pred%d" % (i)) + if not (target is None): + saveOneImg(target[0, i, :, :].data.cpu().numpy(), results_epoch_dir, cate_name,sub_name, "_true%d" % (i)) @@ -172,27 +173,28 @@ def validate(self): results_epoch_dir = osp.join(out,'epoch_%04d' % self.epoch) mkdir(results_epoch_dir) - for batch_idx, (data,target,sub_name) in tqdm.tqdm( - # enumerate(self.test_loader), total=len(self.test_loader), - enumerate(self.test_loader), total=len(self.test_loader), - desc='Valid epoch=%d' % self.epoch, ncols=80, - leave=False): - - if self.cuda: - data, target = data.cuda(), target.cuda() - data, target = Variable(data,volatile=True), Variable(target,volatile=True) - - pred = self.model(data) - - lbl_pred = pred.data.max(1)[1].cpu().numpy()[:,:, :].astype('uint8') - batch_num = lbl_pred.shape[0] - for si in range(batch_num): - curr_sub_name = sub_name[si] - out_img_dir = os.path.join(results_epoch_dir, 'seg') - mkdir(out_img_dir) - out_nii_file = os.path.join(out_img_dir,('%s_seg.nii.gz'%(curr_sub_name))) - seg_img = nib.Nifti1Image(lbl_pred[si], affine=np.eye(4)) - nib.save(seg_img, out_nii_file) + with torch.no_grad(): + for batch_idx, (data,target,sub_name) in tqdm.tqdm( + # enumerate(self.test_loader), total=len(self.test_loader), + enumerate(self.test_loader), total=len(self.test_loader), + desc='Valid epoch=%d' % self.epoch, ncols=80, + leave=False): + + if self.cuda: + data, target = data.cuda(), target.cuda() + data, target = Variable(data,volatile=True), Variable(target,volatile=True) + + pred = self.model(data) + + lbl_pred = pred.data.max(1)[1].cpu().numpy()[:,:, :].astype('uint8') + batch_num = lbl_pred.shape[0] + for si in range(batch_num): + curr_sub_name = sub_name[si] + out_img_dir = os.path.join(results_epoch_dir, 'seg') + mkdir(out_img_dir) + out_nii_file = os.path.join(out_img_dir,('%s_seg.nii.gz'%(curr_sub_name))) + seg_img = nib.Nifti1Image(lbl_pred[si], affine=np.eye(4)) + nib.save(seg_img, out_nii_file) # if self.epoch==0: # lbl_target = target.data.max(1)[1].cpu().numpy()[:,:, :].astype('uint8') @@ -282,17 +284,13 @@ def train_epoch(self): # torch.save(self.model.state_dict(), model_pth) def test_epoch(self): - for epoch in tqdm.trange(self.epoch, self.max_epoch, - desc='Test', ncols=80): - self.epoch = epoch - train_root_dir = osp.join(self.train_root_dir, 'models') - - model_pth = '%s/model_epoch_%04d.pth' % (train_root_dir, epoch) - if os.path.exists(model_pth): - self.model.load_state_dict(torch.load(model_pth)) - self.validate() - - - - - + with torch.no_grad(): + for epoch in tqdm.trange(self.epoch, self.max_epoch, + desc='Test', ncols=80): + self.epoch = epoch + train_root_dir = osp.join(self.train_root_dir, 'models') + + model_pth = '%s/model_epoch_%04d.pth' % (train_root_dir, epoch) + if os.path.exists(model_pth): + self.model.load_state_dict(torch.load(model_pth)) + self.validate() \ No newline at end of file