相互運用性のためにMATLABBuilderNEを使用して、オープンソースアプリケーションClearCanvasのプラグインとして構築されたC#.NETプログラムからMATLAB関数を呼び出しています。.NETプログラムから通常どおりコードを実行すると、通常(常にではありませんが)エラーメッセージが表示されます。
MWMCR::EvaluateFunctionエラー...セル配列の存在しない要素への参照。178行目の=>ComputeT1Maps.mのエラー。
問題のMATLABコードの行は次のとおりです。
seriesHeader = currentSlab.Slice{1}.MetaData{1}.Header;
ヘッダーはMATLABのdicominfo関数によって指定された形式の構造体であり、MetaData{n}はn番目の画像ファイルのファイル名と画像ヘッダー構造体を含む構造体です。
ComputeT1Maps関数の関数シグネチャは次のとおりです。
function ComputeT1Maps(data, options)
このバグを理解するために、ComputeT1Maps関数の先頭に次の行を挿入して状態を保持し、.NETからMATLABに渡された値を確認できるようにしました。
save(fullfile('F:\MATLAB\T1Mapping', 'T1_debug.mat'), 'data', 'options', ...
'-mat', '-v7.3');
したがって、この関数への入力(それを呼び出した.NETプログラムから受け取った)を保持した後、保存された変数を読み込んだ後、インタラクティブなMATLABセッションからComputeT1Maps関数を実行してみました。これにより、MATLABのデバッグツールを利用して計算を行うことができます。エラーが発生した理由を説明します。それは物事が本当に奇妙になったときです。この関数は、.NETプログラムから呼び出されたときに与えられたものとまったく同じオペランドが与えられた場合、インタラクティブなMATLABセッションから問題なく機能します。どうすればいいの?C#.NETから呼び出されたときに関数が失敗するのに、インタラクティブなMATLABセッションでまったく同じ入力が与えられた場合に正しく実行されるのはどうしてですか?また、これと同じコードは以前は機能していましたが、MATLABのローカルインストールとMCRの両方を最新バージョン(2011b)に更新した後にのみエラーが発生し始めました。
.NET側では、data
MATLABに渡されるは次の関数によって作成されます。
public void ExchangeData(MultidimensionalDataCollection mdc, string outputPath, bool generateAncillaryTestImages,
bool excludeAcquisitions, double[] exclusionList, bool showProgressBar, bool displayComputedImages,
bool pauseAtEachSlice, bool softwareDiagnostics, bool displayProgressBar)
{
try
{
int subspaceIndex = 0;
int slabIndex = 0;
int sliceIndex = 0;
int imageIndex = 0;
MWStructArray topLevelGrouping;
MWCellArray geometricSubspaceList;
MWStructArray geometricGrouping;
MWCellArray slabList;
MWStructArray slabGrouping;
MWCellArray sliceList;
MWStructArray sliceGrouping;
MWCellArray imageMetaData;
MWStructArray perImageData;
MWArray[] result;
MWLogicalArray successFlag;
MWStructArray header;
MWCellArray sopInstanceUids;
MWStructArray t1MapOptions;
topLevelGrouping = new MWStructArray(1, 1, new string[] { "GeometricSubspace",
"GeometricSubspaceCount" });
topLevelGrouping["GeometricSubspaceCount", 1] = mdc.Count;
geometricSubspaceList = new MWCellArray(1, mdc.Count);
subspaceIndex = 0;
foreach (GeometricSubspace subspace in mdc)
{
subspaceIndex++;
geometricGrouping = new MWStructArray(1, 1, new string[] { "Slab",
"SlabCount" });
geometricGrouping["SlabCount", 1] = subspace.Count;
slabList = new MWCellArray(1, subspace.Count);
slabIndex = 0;
foreach (Slab slab in subspace)
{
slabIndex++;
slabGrouping = new MWStructArray(1, 1, new string[] { "Slice",
"SliceCount" });
slabGrouping["SliceCount", 1] = slab.Count;
sliceList = new MWCellArray(1, slab.Count);
sliceIndex = 0;
foreach (Slice slice in slab)
{
sliceIndex++;
sliceGrouping = new MWStructArray(1, 1, new string[] {
"ImageCount", "MetaData", "MultidimensionalPixelData",
"SliceLocation", "SopInstanceUids" });
sliceGrouping["ImageCount", 1] = slice.Count;
imageMetaData = new MWCellArray(1, slice.Count);
int rows, columns;
short[,,,] multidimensionalPixelData = null;
imageIndex = 0;
foreach (Image image in slice)
{
imageIndex++;
short[,] imageMatrix = null;
if (!image.ImageSopClass.DicomUid.Equals(DicomUids.MRImageStorage))
throw new NotSupportedException("SopClass " + image.ImageSopClass.Name + " is not supported.");
else
{
DicomUncompressedPixelData rawPixelData = image.PixelData;
imageMatrix = GetCCImageMatrix(rawPixelData, out rows, out columns);
if (imageIndex == 1)
{
multidimensionalPixelData = new short[slice.Count, 1, columns, rows];
}
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < columns; j++)
{
// Remember that C# array indices start with 0 while in MATLAB they start with 1
multidimensionalPixelData[imageIndex - 1, 0, i, j] = imageMatrix[i, j];
}
}
}
perImageData = new MWStructArray(1, 1, new string[] { "FileName", "Header" });
perImageData["FileName", 1] = image.FileName;
result = _mlT1Mapping.QT1GetDicomHeader(2, image.FileName);
if (result == null)
throw new Exception("GetDicomHeader failed to read the header file for filename: " +
image.FileName);
else
{
// MWStructArray
successFlag = (MWLogicalArray)result[0];
bool[] headerObtained = successFlag.ToVector();
if (headerObtained[0])
{
header = (MWStructArray)result[1];
perImageData["Header", 1] = header;
imageMetaData[1, imageIndex] = perImageData;
}
else
{
Console.WriteLine("GetDicomHeader failed to read the header file for filename: " +
image.FileName);
}
}
}
sliceList[1, sliceIndex] = sliceGrouping;
sliceGrouping["MetaData", 1] = imageMetaData;
sliceGrouping["SliceLocation", 1] = slice.SliceLocation;
List<string> theSops = slice._sopList;
sopInstanceUids = new MWCellArray(1, slice._sopList.Count);
int count = 0;
foreach (string sop in theSops)
{
count++;
sopInstanceUids[1, count] = sop;
}
sliceGrouping["SopInstanceUids", 1] = sopInstanceUids;
sliceGrouping["MultidimensionalPixelData", 1] = (MWNumericArray)multidimensionalPixelData;
}
slabList[1, slabIndex] = slabGrouping;
slabGrouping["Slice", 1] = sliceList;
}
geometricSubspaceList[1, subspaceIndex] = geometricGrouping;
geometricGrouping["Slab", 1] = slabList;
}
topLevelGrouping["GeometricSubspace", 1] = geometricSubspaceList;
t1MapOptions = new MWStructArray(1, 1, new string[] { "DirectoryPath",
"ComputeDifferenceImages", "ComputeMultiplicationImages", "DisplayComputedImages", "PauseAtEachSlice",
"SoftwareDiagnostics", "DisplayProgressBar"
});
t1MapOptions["DirectoryPath"] = (MWCharArray)outputPath;
t1MapOptions["SaveS0Maps"] = (MWLogicalArray)generateAncillaryTestImages;
t1MapOptions["ExcludeAcquisitions"] = (MWLogicalArray)excludeAcquisitions;
t1MapOptions["ExclusionList"] = (MWNumericArray)exclusionList;
t1MapOptions["DisplayComputedImages"] = (MWLogicalArray)displayComputedImages;
t1MapOptions["PauseAtEachSlice"] = (MWLogicalArray)pauseAtEachSlice;
t1MapOptions["SoftwareDiagnostics"] = (MWLogicalArray)softwareDiagnostics;
t1MapOptions["DisplayProgressBar"] = (MWLogicalArray)displayProgressBar;
_mlT1Mapping.ComputeT1Maps(topLevelGrouping, t1MapOptions);
}
catch (Exception)
{
throw;
}
}