就像我在评论中说的那样,医学图像配准是一个话题,有很多研究可用,我不是专家。根据我的阅读,常用的基本思想是定义两个图像(在您的情况下为图像及其镜像)之间的映射,然后定义能量项以实现平滑度和图像相似性(如果应用了映射),最后使用标准(或有时是特定于应用程序的)优化技术来优化此映射。
我用Mathematica破解了一个快速算法来演示这一点。这是不是您应该在医疗应用中使用的算法,只是基本概念的演示。
首先,我加载您的图像,对其进行镜像,然后将这些图像分成小块:
src = ColorConvert[Import["http://i.stack.imgur.com/jf709.jpg"],
"Grayscale"];
mirror = ImageReflect[src, Left -> Right];
blockSize = 30;
partsS = ImagePartition[src, {blockSize, blockSize}];
partsM = ImagePartition[mirror, {blockSize, blockSize}];
GraphicsGrid[partsS]
通常,我们会进行近似的刚性配准(例如使用关键点或图像矩),但是您的图像几乎居中,因此我将跳过此过程。
如果我们看一个块,它是对应的镜像:
{partsS[[6, 10]], partsM[[6, 10]]}
我们可以看到它们是相似的,但是发生了变化。我们正在努力寻找转变的数量和方向。
为了量化匹配相似度,我可以使用平方的欧几里德距离:
ListPlot3D[
ImageData[
ImageCorrelate[partsM[[6, 10]], partsS[[6, 10]],
SquaredEuclideanDistance]]]
可悲的是,直接使用此数据进行优化比我想的要难,所以我改用了二阶近似:
fitTerms = {1, x, x^2, y, y^2, x*y};
fit = Fit[
Flatten[MapIndexed[{#2[[1]] - blockSize/2, #2[[2]] -
blockSize/2, #1} &,
ImageData[
ImageCorrelate[partsM[[6, 10]], partsS[[6, 10]],
SquaredEuclideanDistance]], {2}], 1], fitTerms, {x, y}];
Plot3D[fit, {x, -25, 25}, {y, -25, 25}]
该函数与实际的相关函数不同,但是第一步足够接近。让我们为每对块计算一下:
distancesFit = MapThread[
Function[{part, template},
Fit[Flatten[
MapIndexed[{#2[[2]] - blockSize/2, #2[[1]] - blockSize/2, #1} &,
ImageData[
ImageCorrelate[part, template,
SquaredEuclideanDistance]], {2}], 1],
fitTerms, {x, y}]], {partsM, partsS}, 2];
这为我们提供了优化的第一个能量项:
variablesX = Array[dx, Dimensions[partsS]];
variablesY = Array[dy, Dimensions[partsS]];
matchEnergyFit =
Total[MapThread[#1 /. {x -> #2, y -> #3} &, {distancesFit,
variablesX, variablesY}, 2], 3];
variablesX/Y
包含每个块的偏移量,并在应用偏移量的情况下matchEnergyFit
近似原始图像和镜像图像之间的平方欧几里德差。
仅优化此能量将产生较差的结果(如果完全收敛)。我们还希望偏移量是平滑的,在块相似度中,偏移量没有任何意义(例如,沿着直线或在白色背景中)。
因此,我们为光滑度设置了第二个能量项:
smoothnessEnergy = Total[Flatten[
{
Table[
variablesX[[i, j - 1]] - 2 variablesX[[i, j]] +
variablesX[[i, j + 1]], {i, 1, Length[partsS]}, {j, 2,
Length[partsS[[1]]] - 1}],
Table[
variablesX[[i - 1, j]] - 2 variablesX[[i, j]] +
variablesX[[i + 1, j]], {i, 2, Length[partsS] - 1}, {j, 1,
Length[partsS[[1]]]}],
Table[
variablesY[[i, j - 1]] - 2 variablesY[[i, j]] +
variablesY[[i, j + 1]], {i, 1, Length[partsS]}, {j, 2,
Length[partsS[[1]]] - 1}],
Table[
variablesY[[i - 1, j]] - 2 variablesY[[i, j]] +
variablesY[[i + 1, j]], {i, 2, Length[partsS] - 1}, {j, 1,
Length[partsS[[1]]]}]
}^2]];
幸运的是,Mathematica内置了约束优化:
allVariables = Flatten[{variablesX, variablesY}];
constraints = -blockSize/3. < # < blockSize/3. & /@ allVariables;
initialValues = {#, 0} & /@ allVariables;
solution =
FindMinimum[{matchEnergyFit + 0.1 smoothnessEnergy, constraints},
initialValues];
让我们看一下结果:
grid = Table[{(j - 0.5)*blockSize - dx[i, j], (i - 0.5)*blockSize -
dy[i, j]}, {i, Length[partsS]}, {j, Length[partsS[[1]]]}] /.
solution[[2]];
Show[src, Graphics[
{Red,
Line /@ grid,
Line /@ Transpose[grid]
}]]
0.1
之前的因素smoothnessEnergy
是平滑能量相对于图像匹配能量项的相对权重。这些是不同权重的结果:
可能的改进:
- 就像我说的,先执行严格的注册。在白色背景下,基于简单图像瞬间的配准应该可以正常工作。
- 这只是一步。您可以使用在第一步中找到的偏移量,然后在第二步中对其进行改进,也许使用较小的搜索窗口或较小的块大小
- 我读过一些文章,他们完全没有障碍,但是优化了每个像素的偏移量。
- 尝试不同的平滑功能