質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.49%
Unity3D

Unity3Dは、ゲームや対話式の3Dアプリケーション、トレーニングシュミレーション、そして医学的・建築学的な技術を可視化する、商業用の開発プラットフォームです。

Q&A

解決済

2回答

5856閲覧

unity 3D ボリュームレンダリング rawデータからテクスチャ3Dへの変換

911RSR

総合スコア13

Unity3D

Unity3Dは、ゲームや対話式の3Dアプリケーション、トレーニングシュミレーション、そして医学的・建築学的な技術を可視化する、商業用の開発プラットフォームです。

0グッド

0クリップ

投稿2020/11/18 04:58

編集2020/12/13 05:34

Unity 3Dで彫刻ゲームを引き続き作っている者です。

凹みさんのページを参照に、削られた断面にCTデータをdicomとして出力したものをraw変換し、これをテクスチャ3Dしたシェーダを貼りたいと思っています。

http://tips.hecomi.com/entry/2018/01/05/192332

凹みさんにコメントでご質問したのですが、お忙しいのかお返事がないので、こちらでご質問させていただきました。

上記ページのまんなかあたり、pvmをrawデータにするところあたりから躓いています。

pvm2rawがc++のためかうまく起動できず、このページの道筋を正確に終えていないのですが、推測するにpvmデータはCT画像がrawフォーマットで200-500枚程度出力されたフォルダとなるかと思います。

この推測のもとに、次のステップ、
「ちょっとコードが長くてアレですが...、以下のようなコードを書くと、RAW データをそのまま 3D テクスチャとして使えるようになります。」

「RAW データをドラッグ&ドロップすると次の図のように public 変数がインスペクタに表示されます。enum がプルダウンにならないのがアレですが...、鯉のデータは 256 * 256 * 512、16 bit なので、そうなるよう入力し、Apply ボタンを押します。」

とありますが、rawデータをドラッグ&ドロップとは、このフォルダごとプロジェクトウィンドウにドラッグすればよいということでしょうか。(ちなみにdicomファイルをdngに変換はできたのですが、rawに変換するのも苦慮しています。。)

いろいろと疑問ばかりで申し訳ございませんが、少しでも先達の方々のお知恵を拝借できれば幸甚です。
よろしくお願いいたします。

12/10追記
無事Texture3Dは生成できたのですが、オブジェクトへの適用でつまずいております。。

引き続き上記、凹みさんのページを参照し、Texture3Dを参照するシェーダのスクリプトを書いたのですが、オブジェクトにドラッグ&ドロップできません。。

C#

1Shader "VolumeRendering/3D Texture" 2{ 3 4 Properties 5 { 6 _Volume("Volume", 3D) = "" {} 7 } 8 9 CGINCLUDE 10 11#include "UnityCG.cginc" 12 13 struct appdata 14 { 15 float4 vertex : POSITION; 16 }; 17 18 struct v2f 19 { 20 float4 vertex : SV_POSITION; 21 float3 uv : TEXCOORD0; 22 }; 23 24 sampler3D _Volume; 25 26 v2f vert(appdata v) 27 { 28 v2f o; 29 o.vertex = UnityObjectToClipPos(v.vertex); 30 float4 wpos = mul(unity_ObjectToWorld, v.vertex); 31 o.uv = wpos.xyz * 0.5 + 0.5; 32 return o; 33 } 34 35 fixed4 frag(v2f i) : SV_Target 36 { 37 return tex3D(_Volume, i.uv); 38 } 39 40 ENDCG 41 42 SubShader 43 { 44 45 Tags 46 { 47 "RenderType" = "Opaque" 48 } 49 50 Pass 51 { 52 CGPROGRAM 53 #pragma vertex vert 54 #pragma fragment frag 55 ENDCG 56 } 57 58 } 59 60} 61コード

毎度毎度初歩的な質問ばかりで申し訳ございません。。

適用しているオブジェクトが、sphereを楕円球にしたものを複数合成させたものになりますので、形状が複雑だから適用できないのかと思い単純なCubeにもD&Dを試みたのですが、やはり無理でした。。

texture3Dの適用には何か独特な手順が必要なのでしょうか。
ご教示頂けますと幸甚です。

***12/13追記
テクスチャ3Dを反映できました!ここまで本当にありがとうございます。

あと一歩、いや1.5歩のように思います!

例のsphereの合成体にこのテクスチャ3Dを反映したところ、以下の結果が得られました。
現状

理想的には、下の図の緑の部分のように、例えばinspecterで表示される地球儀マップ状のテクスチャを、そのままsphereの合成体に貼り付けたいと思っています。
緑の部分を切り抜いて
↓理想とする結果
理想の結果

現状ではsphere上にテクスチャ3Dが繰り返し表示され、また目的の場所が切り取られないというのが問題に思いますが、スクリプトを改変することで理想は達成できそうでしょうか。
自動的に必要な部分のuv座標を計算させ、リアルタイムに反映させるのは難しいように思いますので、少なくともtiling等をいじって画像が何列もダブって表示されるのだけでも解消しようと試みたのですが、tilingを0.1や10等に変えてもテクスチャ自体には変化が起こりませんでした。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

##タイリング、オフセットを調整できるように改造

設定項目を追加してみました。それぞれの項目で使われるのはX、Y、Zの3成分ですが、インスペクター上では不要なWまで表示されてしまい若干見苦しくはあります。インスペクター用のスクリプトを用意すればもっとマシな見た目になるだろうと思いますが、手抜きしました...

ShaderLab

1Shader "VolumeRendering/3D Texture" 2{ 3 Properties 4 { 5 // デフォルト状態ではVolume欄にTilingとOffsetが表示されてしまうが、これは3次元では役に立たない 6 // これらが表示されていると紛らわしいため、NoScaleOffset属性を付けて隠してしまう 7 [NoScaleOffset] _Volume("Volume", 3D) = "" {} 8 9 // 代わりに、独自にTilingと... 10 _Tiling("Tiling", Vector) = (1, 1, 1, 0) 11 12 // Offsetを定義する 13 _Offset("Offset", Vector) = (0, 0, 0, 0) 14 15 // さらに利便性の観点から、シェーダーにテクスチャサイズを伝えられるようにする 16 // 2Dテクスチャであれば(テクスチャ名)_TexelSizeの形のユニフォーム変数を宣言すると 17 // 自動的にテクスチャサイズを取得できるのだが、3DテクスチャではZ軸もあるため 18 // 利用できないので、面倒だが入力欄に手動でサイズを入力しなければならない 19 // 補助的なスクリプトを用意することでいくらかは自動化することも可能なはずだが、 20 // 説明がかえってややこしくなりそうで省略した 21 _Size("Texture Size", Vector) = (256, 256, 256, 0) 22 } 23 24 CGINCLUDE 25 26 #include "UnityCG.cginc" 27 28 struct appdata 29 { 30 float4 vertex : POSITION; 31 }; 32 33 struct v2f 34 { 35 float4 vertex : SV_POSITION; 36 float3 uv : TEXCOORD0; 37 }; 38 39 sampler3D _Volume; 40 41 // シェーダー内でプロパティと対応するユニフォーム変数を宣言すると、レンダリング時に自動的に 42 // プロパティの値がセットされるので、シェーダーコード上でその値を利用できる 43 float3 _Tiling; 44 float3 _Offset; 45 float3 _Size; 46 47 v2f vert(appdata v) 48 { 49 v2f o; 50 o.vertex = UnityObjectToClipPos(v.vertex); 51 float4 wpos = mul(unity_ObjectToWorld, v.vertex); 52 53 // テクスチャの縦・横・奥行きが異なっているケースも多いと思われる 54 // たとえば実験で使ったHeadは512x512x245だが、これをサンプリングするときの座標は0~1に 55 // 正規化されているため、ちゃんと対策しないと長さの短いZ方向だけ伸びて見えてしまうかもしれない 56 // そこで3軸のアスペクト比を求めておく 57 float3 texelSize = 1.0 / _Size; 58 float3 aspect = max(max(_Size.x, _Size.y), _Size.z) * texelSize; 59 60 // テクスチャ座標を_Tiling、aspectに応じて拡大・縮小し、_Offsetに応じてずらすようにする 61 // _OffsetはtexelSizeをかけることで値をテクスチャのピクセル単位で解釈することにした 62 o.uv = wpos.xyz * _Tiling * aspect + _Offset * texelSize; 63 64 return o; 65 } 66 67 fixed4 frag(v2f i) : SV_Target 68 { 69 return tex3D(_Volume, i.uv); 70 } 71 72 ENDCG 73 74 SubShader 75 { 76 Tags 77 { 78 "RenderType" = "Opaque" 79 } 80 81 Pass 82 { 83 CGPROGRAM 84 #pragma vertex vert 85 #pragma fragment frag 86 ENDCG 87 } 88 } 89}

図

投稿2020/12/13 13:03

編集2020/12/15 10:41
Bongo

総合スコア10807

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

911RSR

2020/12/16 07:40

思っていたことにかなり近いことが実装できました! 本当にすごいです。 長きにわたって本当にありがとうございました!
guest

0

「rawデータをドラッグ&ドロップ」とあるのは、pvm2rawで処理してできあがった単一のファイルをプロジェクトビューに放り込むことを指していると思われます。するとPvmRawImporterによって自動的にTexture3Dになるということでしょう。普通の画像ファイルをプロジェクトビューに入れれば自動的にTexture2Dとして扱えるのと同じ使い勝手のようですね。

ですがRAWデータを作るところで難儀していらっしゃるのなら、そこから何とかしなければならないでしょう。
何かお役に立ちそうなものがないか検索したところ、fo-dicomなんてものがありました。説明文にあるように、

C#

1var image = new DicomImage("imagename.dcm"); 2var texture = image.RenderImage().AsTexture2D();

だけでTexture2Dができあがるという親切お手軽設計でした。そこで凹みTipsさんとはちょっと違ったアプローチですが、まずfo-dicomをインポートした上で、プロジェクト内にEditorフォルダを作って下記のようなスクリプトを置き...

C#

1using System; 2using System.IO; 3using System.Linq; 4using Dicom.Imaging; 5using UnityEditor; 6using UnityEngine; 7using Object = UnityEngine.Object; 8 9public static class DicomFilesToTexture3D 10{ 11 [MenuItem("Utility/DICOM/Create Texture3D from DICOM files")] 12 private static void CreateTexture3DFromDicomFiles() 13 { 14 // まずフォルダ選択ダイアログを出し、DICOMファイル群が収められたフォルダを選んでもらう 15 var sourceFolderPath = EditorUtility.OpenFolderPanel( 16 "Choose a folder that contains DICOM (*.dcm, *.dic) images", 17 string.Empty, 18 string.Empty); 19 if (string.IsNullOrEmpty(sourceFolderPath)) 20 { 21 return; 22 } 23 24 if (!Directory.Exists(sourceFolderPath)) 25 { 26 EditorUtility.DisplayDialog("Invalid source", "Choose a valid source folder.", "OK"); 27 return; 28 } 29 30 // フォルダ内でファイル名が「.dcm」または「.dic」で終わるものを抜き出してファイルパスを得る 31 var sourceFilePaths = Directory.EnumerateFiles(sourceFolderPath).Where( 32 path => !string.IsNullOrEmpty(path) && 33 (path.EndsWith(".dcm", StringComparison.OrdinalIgnoreCase) || 34 path.EndsWith(".dic", StringComparison.OrdinalIgnoreCase))) 35 .OrderBy(path => path).ToArray(); 36 var sourceFileCount = sourceFilePaths.Length; 37 if (sourceFileCount <= 0) 38 { 39 EditorUtility.DisplayDialog("Invalid source", "No DICOM images were found.", "OK"); 40 return; 41 } 42 43 // ひとまず最初のファイルからDicomImageを作り、できあがるであろうTexture3Dの 44 // サイズ見積もりを提示し、続行するかどうか確認する 45 var firstFilePath = sourceFilePaths.First(); 46 DicomImage firstImage; 47 try 48 { 49 firstImage = new DicomImage(firstFilePath); 50 } 51 catch (Exception e) 52 { 53 EditorUtility.DisplayDialog("Failed", $"{e.GetType()}\n{e.Message}", "OK"); 54 throw; 55 } 56 57 var dimension = new Vector3Int( 58 firstImage.Width, 59 firstImage.Height, 60 firstImage.NumberOfFrames > 1 ? firstImage.NumberOfFrames : sourceFileCount); 61 var resultSize = dimension.x * dimension.y * dimension.z * 4; 62 var resultSizeInKib = resultSize / 1024.0; 63 var resultSizeInMib = resultSizeInKib / 1024.0; 64 var resultSizeInGib = resultSizeInMib / 1024.0; 65 if (!EditorUtility.DisplayDialog( 66 "Confirm Texture3D data size", 67 $"The resulting Texture3D data size will be {resultSize} bytes ({(resultSizeInGib >= 1.0 ? $"{resultSizeInGib:0.##} GB" : resultSizeInMib >= 1.0 ? $"{resultSizeInMib:0.##} MB" : $"{resultSizeInKib:0.##} KB")}). Are you sure want to continue?", 68 "Continue", 69 "Cancel")) 70 { 71 return; 72 } 73 74 Texture3D resultTexture; 75 if (firstImage.NumberOfFrames > 1) 76 { 77 // DICOMは1つのファイルに複数枚のフレームを持つこともできるらしい? 78 // それらフレームが個々の断面を表しているケースもあるのかもしれない...と思い 79 // 先ほど作ったDicomImageに複数のフレームが格納されている場合は、それぞれの 80 // フレームを断面と見なすことにし、もしフォルダ内に他のDICOMファイルが入っていたとしても 81 // それらは無視することにした 82 if ((sourceFileCount > 1) && !EditorUtility.DisplayDialog( 83 "Texture3D will be created from single file", 84 $"{sourceFileCount} DICOM images exist in the folder {Path.GetFileName(sourceFolderPath)}, but file {Path.GetFileName(firstFilePath)} has multiple frames and the Texture3D slices will be taken from this file. All other files will be ignored.", 85 "Continue", 86 "Cancel")) 87 { 88 return; 89 } 90 91 // まずTexture3Dを生成して... 92 resultTexture = new Texture3D(dimension.x, dimension.y, dimension.z, TextureFormat.RGBA32, false); 93 for (var i = 0; i < firstImage.NumberOfFrames; i++) 94 { 95 // 各フレームからUnityImageを生成、さらにそれからTexture2Dを生成して 96 // そのデータをTexture3Dにコピー、最後に用済みのTexture2Dを削除する 97 try 98 { 99 using (var tempImage = firstImage.RenderImage(i)) 100 { 101 var tempTexture = tempImage.AsTexture2D(); 102 Graphics.CopyTexture(tempTexture, 0, 0, resultTexture, i, 0); 103 Object.DestroyImmediate(tempTexture); 104 } 105 } 106 catch (Exception e) 107 { 108 EditorUtility.DisplayDialog("Failed", $"{e.GetType()}\n{e.Message}", "OK"); 109 Object.DestroyImmediate(resultTexture); 110 throw; 111 } 112 } 113 } 114 else 115 { 116 // 最初に調べた1枚目のDicomImageがシングルフレームだったなら、 117 // 断面がそれぞれ1ファイルずつに分けられているものと想定する 118 // まずTexture3Dを生成して... 119 resultTexture = new Texture3D(dimension.x, dimension.y, dimension.z, TextureFormat.RGBA32, false); 120 for (var i = 0; i < sourceFilePaths.Length; i++) 121 { 122 // フォルダ内のファイルを1つずつ列挙し、DicomImageを作る 123 var sourceFilePath = sourceFilePaths[i]; 124 var sourceFileName = Path.GetFileName(sourceFilePath); 125 DicomImage image; 126 try 127 { 128 image = new DicomImage(sourceFilePath); 129 } 130 catch (Exception e) 131 { 132 EditorUtility.DisplayDialog("Failed", $"{e.GetType()}\n{e.Message}", "OK"); 133 Object.DestroyImmediate(resultTexture); 134 throw; 135 } 136 137 // こちらのケースでは1つのファイルが1つの断面を表していることを前提としており、 138 // もしそこに複数フレームを持つファイルがまぎれ込んでいたら異常事態と見なして中断する 139 if (image.NumberOfFrames > 1) 140 { 141 EditorUtility.DisplayDialog( 142 "Invalid source", 143 $"A multi-frame image {sourceFileName} was found.", 144 "OK"); 145 Object.DestroyImmediate(resultTexture); 146 return; 147 } 148 149 // また、すべての断面は幅・高さが同じでないとまずいため、 150 // もしそうでないファイルがまぎれ込んでいた場合も中断する 151 if ((image.Width != dimension.x) || (image.Height != dimension.y)) 152 { 153 EditorUtility.DisplayDialog( 154 "Invalid source", 155 $"All images should be the same size. The expected size is ({dimension.x}, {dimension.y}), but the size of image {sourceFileName} is ({image.Width}, {image.Height})", 156 "OK"); 157 Object.DestroyImmediate(resultTexture); 158 return; 159 } 160 161 // DicomImageからUnityImageを生成、さらにそれからTexture2Dを生成して 162 // そのデータをTexture3Dにコピー、最後に用済みのTexture2Dを削除する 163 try 164 { 165 using (var tempImage = image.RenderImage()) 166 { 167 var tempTexture = tempImage.AsTexture2D(); 168 Graphics.CopyTexture(tempTexture, 0, 0, resultTexture, i, 0); 169 Object.DestroyImmediate(tempTexture); 170 } 171 } 172 catch (Exception e) 173 { 174 EditorUtility.DisplayDialog("Failed", $"{e.GetType()}\n{e.Message}", "OK"); 175 Object.DestroyImmediate(resultTexture); 176 throw; 177 } 178 } 179 } 180 181 // セーブダイアログを出してアセットの名前、保存場所を決めてもらい... 182 var destinationPath = EditorUtility.SaveFilePanelInProject( 183 "Save Texture3D", 184 "DICOM Texture", 185 "asset", 186 "Enter an asset name for the Texture3D."); 187 if (string.IsNullOrEmpty(destinationPath)) 188 { 189 Object.DestroyImmediate(resultTexture); 190 return; 191 } 192 193 // できあがったTexture3Dをアセットファイル化して保存する 194 AssetDatabase.CreateAsset(resultTexture, destinationPath); 195 AssetDatabase.SaveAssets(); 196 } 197 198 // fo-dicomの作るTexture2DがRGBA32フォーマットだったので生成されるTexture3Dのフォーマットも 199 // RGBA32にしたものの、今回のようなグレースケールに4チャンネルも使うのはもったいなく思い 200 // 生成されたRGBA32のTexture3DからRだけを抜き出してR8フォーマット版を作るメソッドも用意した 201 [MenuItem("Utility/DICOM/Convert Texture3D format from RGBA32 to/R8")] 202 private static void ConvertToR8() 203 { 204 ConvertTo(DestinationFormat.R8); 205 } 206 207 // こちらは抜き出したRをAとして扱わせる 208 [MenuItem("Utility/DICOM/Convert Texture3D format from RGBA32 to/Alpha8")] 209 private static void ConvertToAlpha8() 210 { 211 ConvertTo(DestinationFormat.Alpha8); 212 } 213 214 private static void ConvertTo(DestinationFormat format) 215 { 216 var targetTexture = Selection.activeObject as Texture3D; 217 if ((targetTexture == null) || (targetTexture.format != TextureFormat.RGBA32)) 218 { 219 return; 220 } 221 222 var newData = targetTexture.GetPixels32(0).Select(c => c.r).ToArray(); 223 var newTexture = new Texture3D( 224 targetTexture.width, 225 targetTexture.height, 226 targetTexture.depth, 227 (TextureFormat)format, 228 false); 229 newTexture.SetPixelData(newData, 0); 230 var destinationPath = EditorUtility.SaveFilePanelInProject( 231 "Save Texture3D", 232 $"{targetTexture.name} {format}", 233 "asset", 234 "Enter an asset name for the Texture3D."); 235 if (string.IsNullOrEmpty(destinationPath)) 236 { 237 Object.DestroyImmediate(newTexture); 238 return; 239 } 240 241 AssetDatabase.CreateAsset(newTexture, destinationPath); 242 AssetDatabase.SaveAssets(); 243 } 244 245 private enum DestinationFormat 246 { 247 R8 = TextureFormat.R8, 248 Alpha8 = TextureFormat.Alpha8 249 } 250}

実験材料としてMR Research Facility :: Visible Human Project Datasetsから入手した「Visible Male CT Datasets」の「Head」を読ませてみたところ、下図のようなTexture3Dを作成できました。

図1

RGBA32だとさすがにサイズがかさむので、1チャンネル化してしまってもいいでしょう。
R8だと...

図2

Alpha8だと...

図3

となり、いずれもサイズが1/4になっています。

せっかくなのでオブジェクトに適用してみました。なおテクスチャ自体はグレーですが、下図では階調に応じて着色し見やすくしてあります。Z方向にも次元を持つテクスチャですので、任意の向きで断面を描かせることができました。

図4

##Unity 2019.4.13f1で見たHeadの様子

図5

投稿2020/11/21 03:46

編集2020/12/01 10:32
Bongo

総合スコア10807

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

911RSR

2020/11/22 10:36

Bongoさん、いつもありがとうございます。 今回も大変、大変ご丁寧なご回答、本当にありがとうございます。 今出先なのですが、週明けにゆっくり確認させてください! 本当にありがとうございます。
911RSR

2020/11/24 06:11

Bongoさん、ありがとうございます。確認してみました。 fo dicomをインポートし、ProjectウィンドウにEditorフォルダを作成、この中にご教示頂きましたスクリプトを書きました。 「「Visible Male CT Datasets」の「Head」を読ませてみたところ、」←これが具体的にどのような手順を踏めばよいでしょうか。 ローカルのdicomファイルが格納されたフォルダをスクリプトの上にドラッグ&ドロップするということでしょうか。初心者過ぎて本当に申し訳ございません。
Bongo

2020/11/24 06:57 編集

説明が足りずすみません。Unityのメニューバー上に「Utility」→「DICOM」→「Create Texture3D from DICOM files」というメニューが出現してはいませんでしょうか? そのメニューを実行するとフォルダ選択ダイアログが開くはずですので、DICOMファイルの入っているフォルダを選んでみてください。 ちなみに、fo-dicomのアセット紹介文で言及されているように、fo-dicomは現状圧縮フォーマットに対応していないらしく、もし圧縮フォーマットのDICOMファイルがまぎれ込んでいるとエラーメッセージを出して失敗するはずです。 もしそうなってしまうなら、可能であれば別な手を考えてみようと思います。 その場合、差し支えなければご質問者さんが利用しようとしているDICOMファイル(石の断面図?)をご提示いただけますでしょうか。それぞれの断面が多数のDICOMファイルになっている場合、その内の一つ...例えば最初の一枚だけでもかまいません。何とかしてそのファイルから二次元の画像を取り出す方法が見つかれば、あとは回答に提示しましたスクリプトと同様の要領でTexture3Dを組み立てることができるはずだと思うのですが...
911RSR

2020/11/25 11:32

Bongoさん、いつもいつも本当にありがとうございます! texture3Dが合成できました! が、手持ちのDICOMファイルがおかしいのか、画像がダブって表示されますので、他のDICOMファイルをいくつか読み込んで数日内に試してみようと思います。 (また進捗状況をこちらにコメントさせていただいて宜しいでしょうか?) いつもいつも本当にありがとうございます。少し道筋が見えてきたように思います。 本当にありがとうございます。
911RSR

2020/12/01 02:50

Bongoさま、大変お待たせしてしまい申し訳ございません。 手持ちのDICOMではtextureは生成されるのですが、4方向くらいにダブって生成されてしまいます。 試しにご教示頂いたウェブサイトからmale headを読み込もうとしているのですが、 (実験材料としてMR Research Facility :: Visible Human Project Datasetsから入手した「Visible Male CT Datasets」の「Head」を読ませてみたところ、) google chromeのimage downloaderの過程でjpgに変換されてしまいうまくいきませんでした。。 宜しければ直接ご質問させていただきたいのですが、運営されていらっしゃるウェブサイト等、コンタクトさせていただけるところはございますでしょうか。 長きにわたり本当に申し訳ございません。
Bongo

2020/12/01 03:51

自前のDICOMだと4方向にダブってしまうという点は謎ですね...そのダブった様子のスクリーンショットをご提示いただけますでしょうか。 未確認ですが「画像が横方向に4回繰り返して表示される」とかですと、もしかしたらfo-dicomがシングルチャンネルのファイルを4チャンネルのファイルと誤認識してしまう...みたいな理由があるのかもしれません。特別な対応が必要かもしれませんね。 Headがうまくいかない件ですが、もしかして「Individual DICOM Files」の方のリンク先にある個々の画像のサムネイルをダウンロードしてしまったんですかね? 「Regional Tar Files (download)」の方のリンクから「VHMCT1mm_Head.tar.gz」というファイル名のアーカイブをダウンロードできるかと思います。それを展開すると中にDICOMファイルがたくさん入っているはずですので、それで試してみてください。 連絡先については、あいにくWebサイトとかは持っておらず、Teratail上くらいしかないんですよね... とはいえTeratailは趣味でちょくちょく覗いており、コメントなどいただいた際には通知欄で気付くはずですので、お返事できるかと思います。 人によっては質問・回答が長丁場になるのを嫌う場合もあるでしょうが、私の場合は特に頓着しませんのでお気軽にコメントください。
911RSR

2020/12/01 05:27

Bongoさん、ありがとうございます。 手持ちの同じようなhead CT画像になります。高精細であることが必要なので、thin sliceで撮影しており、合計800枚程度くらいになることもあります。このため、画像の折り返しと判定されているのでしょうか。。 (画像種類の性格上、秘匿性の高いコミュニケーション方法があればな、と希望させていただいた次第です。現状では大丈夫ですので、Bongoさんのお好みに合わさせて頂きます。)よろしくお願いいたします。
Bongo

2020/12/01 10:33 編集

ダブって見えてしまうとおっしゃるのは、質問文に追記いただいたテクスチャプレビューの様子のことでしょうか? だとしたら、それは気にする必要はないかもしれません。 Unityのバージョンはいくつでしょうか。私は回答に示しました実験をバージョン2020.1.11f1上で行ったのですが、Headを読み込んでできあがった「DICOM Texture.asset」ファイルをバージョン2019.4.13f1のプロジェクト内にインポートしてみたところ、追記しました図のようなヘンテコなプレビューになってしまいました。 どうやら旧バージョンにはTexture3D用のプレビューが搭載されていない様子です。凹みTipsさんの記事にも中ほどにCarpテクスチャのプレビューの様子が掲載されておりますが、あちらも球体の表面にテクスチャの中心がずれた状態で描画されて、あたかも4分割されているような見た目になっています。 「画像種類の性格上」とのこと、なるほど納得いたしました。あいにく私はDICOMについては名前くらいしか聞いたことがなかったのですが、今回の件で調べてみると患者さんの個人情報だとかも格納できるかなり高機能なフォーマットのようですね。となると、以前のコメントで申し上げたようなDICOMファイルの現物をご提示いただければ...みたいなことは難しい事情があるのかもしれないとお察しします。私もどこぞの馬の骨の一人ですので、機密性の高い情報を出す必要があるような要求はご遠慮なく突っぱねてください。
911RSR

2020/12/03 10:32

Bongoさん、いつもご親切に本当にありがとうございます。 問題ないかもしれないとの件、とてもうれしかったです。versionは2019.4.6f1を使用しております。他の共同研究者と合わせている都合上、最新のものにアップデートするのは少しハードルが高いかもしれません。 また少し私の方でいじってみますので少しお時間を頂けますと幸甚です。 またコメント、質問させていただいたときは、再度のお願いで大変恐縮ではございますが何卒よろしくお願い申し上げます。 画像の方は当方で扱う前に匿名化処理をしておりますし上記の内容は全く問題ないです。(それでも時間がたったら削除依頼をサイトに出すかもしれません。) 繰り返しになりますが、本当にありがとうございます。
911RSR

2020/12/10 02:46

生成されたテクスチャの適用方法がわからず、、、初歩的な質問ばかりで申し訳ございません。
Bongo

2020/12/10 19:46

ご提示のシェーダーコードを試してみましたが、ちゃんと動作するようでした。 「オブジェクトにドラッグ&ドロップできない」とおっしゃるのは、もしかして作成したシェーダーファイル(虹色の紙に「S」の字が書かれたアイコン)そのものをオブジェクトにドラッグ&ドロップしようとしているということでしょうか? もしそうでしたら、そうではなくてまずマテリアルを作成してやる必要があるはずです。 新しくマテリアルを作成し、マテリアルのインスペクターを表示させると、最上部のマテリアル名の直下に「Shader」とラベルがついたポップアップメニューがあるはずですが、ここで目的のシェーダーを探して選択してください(ご提示のシェーダーの場合「VolumeRendering」→「3D Texture」にあるはずです)。 するとインスペクターの表示内容が選択したシェーダーに合わせた設定項目に変化するはずですので、項目を設定し(とはいえ「Volume」にTexture3Dをセットするぐらいしかやることはないでしょうが...)、そしてマテリアルをオブジェクトにドラッグ&ドロップすればそのオブジェクトにマテリアルが適用されるはずです。 Texture3Dを使っているからといって特別な手順を踏まなければならない...といったことはなく、一般的なTexture2Dを使ったシェーダーや、あるいはテクスチャを必要としないシェーダーであっても、手順的には変わらないと思います。 ちなみに、プロジェクトビュー内のシェーダーファイルを選択した状態で新規マテリアルを作成すると、最初からShaderメニューにそのシェーダーが選択された状態でマテリアルが作成されますので、ちょっと操作の手間が軽減されますね。
911RSR

2020/12/13 05:35

Bongoさん、いつも本当にありがとうございます。初歩的な問題であったようで大変失礼いたしました。ご指導いただきました通りに作業しますと、テクスチャ3Dを無事反映できるようになりました! 画像の取得位置、サイズについて調整が必要なようで、質問に追記させていただきました。
Bongo

2020/12/13 13:04

TilingやOffsetにご注目なさったのは鋭いと思いますが、あの設定項目はTexture2D向けの設定であり、しかもシェーダー内で設定値に応じてテクスチャサンプリング位置を操作するようなコードになっていないと効果を発揮しないはずです。 現状のコードでは、サンプリング位置を... float4 wpos = mul(unity_ObjectToWorld, v.vertex); o.uv = wpos.xyz * 0.5 + 0.5; という風にワールド座標だけしか利用せずに決定していますので、テクスチャの貼られ方を調整する余地がない状態と言えるでしょう。 ここは貼られ方を調整できるようマテリアルにプロパティを追加してやる必要があるでしょうね。改造案を検討してみましたので追記したかったのですが、字数の限界に到達してしまったため、すみませんが別回答に移ります。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.49%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問