Yorumlarda söylediğim gibi, tıbbi görüntü kaydı birçok araştırmanın mevcut olduğu bir konudur ve ben uzman değilim. Okuduğum kadarıyla, yaygın olarak kullanılan temel fikir, iki görüntü (sizin durumunuzda bir görüntü ve ayna görüntüsü) arasında bir eşleme tanımlamak, ardından eşleme uygulanırsa pürüzsüzlük ve görüntü benzerliği için enerji terimlerini tanımlamak ve son olarak standart (veya bazen uygulamaya özgü) optimizasyon tekniklerini kullanarak bu eşlemeyi optimize edin.
Bunu göstermek için Mathematica'da hızlı bir algoritmayı hackledim. Bu, tıbbi bir uygulamada kullanmanız gereken bir algoritma değil , sadece temel fikirlerin bir gösterisidir.
İlk olarak, görüntünüzü yüklüyorum, yansıtıyorum ve bu görüntüleri küçük bloklara ayırıyorum:
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]
Normalde, yaklaşık bir katı kayıt yapardık (örneğin, anahtar noktaları veya görüntü anları kullanarak), ancak görüntünüz neredeyse ortalanmış, bu yüzden bunu atlayacağım.
Bir bloğa bakarsak ve bu ayna görüntüsü muadili ise:
{partsS[[6, 10]], partsM[[6, 10]]}
Benzer olduklarını görebiliyoruz, ama değişti. Vardiya miktarı ve yönü bulmaya çalıştığımız şeydir.
Eşleşme benzerliğini ölçmek için, kareli öklid mesafesini kullanabilirim:
ListPlot3D[
ImageData[
ImageCorrelate[partsM[[6, 10]], partsS[[6, 10]],
SquaredEuclideanDistance]]]
ne yazık ki, bu verileri kullanarak optimizasyon doğrudan düşündüğümden daha zordu, bu yüzden bunun yerine 2. dereceden bir yaklaşım kullandım:
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}]
İşlev, gerçek korelasyon işleviyle aynı değildir, ancak ilk adım için yeterince yakındır. Bunu her blok çifti için hesaplayalım:
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];
Bu bize optimizasyon için ilk enerji terimimizi verir:
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
her blok için ofsetleri içerir ve matchEnergyFit
orijinal görüntü ile yansıtılan görüntü arasındaki kareli öklid farkını, ofsetler uygulayarak yaklaşık olarak gösterir.
Bu enerjiyi tek başına optimize etmek kötü sonuçlar verir (hiç yakınsa). Ayrıca, ofsetlerin pürüzsüz olmasını istiyoruz, burada blok benzerliği ofset hakkında hiçbir şey söylemez (örneğin düz bir çizgi boyunca veya beyaz arka planda).
Böylece pürüzsüzlük için ikinci bir enerji terimi belirledik:
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]];
Neyse ki, Mathematica'da kısıtlı optimizasyon yerleşiktir:
allVariables = Flatten[{variablesX, variablesY}];
constraints = -blockSize/3. < # < blockSize/3. & /@ allVariables;
initialValues = {#, 0} & /@ allVariables;
solution =
FindMinimum[{matchEnergyFit + 0.1 smoothnessEnergy, constraints},
initialValues];
Sonuca bakalım:
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]
}]]
Önceki 0.1
faktör smoothnessEnergy
, pürüzsüzlük enerjisinin görüntü eşleme enerji terimi ile ilişkili olarak aldığı nispi ağırlıktır. Bunlar farklı ağırlıklar için sonuçlardır:
Olası iyileştirmeler:
- Dediğim gibi, önce katı bir kayıt yapın. Beyaz bir arka plan ile, basit görüntü anları tabanlı kayıt iyi çalışmalıdır.
- Bu sadece bir adım. Bulduğunuz ofsetleri bir adımda kullanabilir ve ikinci bir adımda iyileştirebilirsiniz, belki daha küçük bir arama penceresi veya daha küçük blok boyutları ile
- Bunu hiç bloklar olmadan yaptıkları makaleleri okudum, ancak piksel başına bir ofseti optimize ettim.
- Farklı pürüzsüzlük işlevlerini deneyin