Seperti yang telah saya katakan di komentar, pendaftaran gambar medis adalah topik dengan banyak penelitian yang tersedia, dan saya bukan ahli. Dari apa yang saya baca, ide dasar yang umum digunakan adalah untuk mendefinisikan pemetaan antara dua gambar (dalam kasus Anda gambar dan gambar cerminnya), kemudian menentukan istilah energi untuk kelancaran dan untuk kesamaan gambar jika pemetaan diterapkan, dan akhirnya optimalkan pemetaan ini menggunakan teknik optimisasi standar (atau terkadang khusus aplikasi).
Saya telah meretas bersama algoritma cepat di Mathematica untuk menunjukkan ini. Ini bukan algoritma yang harus Anda gunakan dalam aplikasi medis, hanya demonstrasi dari ide-ide dasar.
Pertama, saya memuat gambar Anda, mirror dan membagi gambar-gambar ini menjadi blok-blok kecil:
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]
Biasanya, kami akan melakukan perkiraan pendaftaran yang kaku (menggunakan mis. Titik kunci atau momen gambar), tetapi gambar Anda hampir terpusat, jadi saya akan melewati ini.
Jika kita melihat satu blok dan itu adalah mirror-image counterpart:
{partsS[[6, 10]], partsM[[6, 10]]}
Kita dapat melihat bahwa mereka serupa, tetapi bergeser. Jumlah dan arah perubahan adalah apa yang kami coba cari tahu.
Untuk menghitung kesamaan pertandingan, saya bisa menggunakan jarak euclide kuadrat:
ListPlot3D[
ImageData[
ImageCorrelate[partsM[[6, 10]], partsS[[6, 10]],
SquaredEuclideanDistance]]]
Sayangnya, menggunakan data ini adalah pengoptimalan secara langsung lebih sulit dari yang saya kira, jadi saya menggunakan perkiraan urutan kedua sebagai gantinya:
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}]
Fungsi ini tidak sama dengan fungsi korelasi aktual, tetapi cukup dekat untuk langkah pertama. Mari kita hitung ini untuk setiap pasangan blok:
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];
Ini memberi kami istilah energi pertama kami untuk optimasi:
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
berisi offset untuk setiap blok, dan matchEnergyFit
mendekati perbedaan euclide kuadrat antara gambar asli dan gambar cermin dengan offset yang diterapkan.
Mengoptimalkan energi ini saja akan memberikan hasil yang buruk (jika konvergen sama sekali). Kami juga ingin offset menjadi halus, di mana kesamaan blok tidak menunjukkan apa-apa tentang offset (misalnya di sepanjang garis lurus atau di latar belakang putih).
Jadi kami menyiapkan istilah energi kedua untuk kelancaran:
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]];
Untungnya, optimasi terbatas ada di dalam Mathematica:
allVariables = Flatten[{variablesX, variablesY}];
constraints = -blockSize/3. < # < blockSize/3. & /@ allVariables;
initialValues = {#, 0} & /@ allVariables;
solution =
FindMinimum[{matchEnergyFit + 0.1 smoothnessEnergy, constraints},
initialValues];
Mari kita lihat hasilnya:
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]
}]]
The 0.1
Faktor sebelum smoothnessEnergy
adalah bobot relatif energi kelancaran mendapat dalam kaitannya dengan istilah gambar energi pertandingan. Ini adalah hasil untuk bobot yang berbeda:
Kemungkinan peningkatan:
- Seperti yang saya katakan, lakukan registrasi yang kaku dulu. Dengan latar belakang putih, registrasi berbasis momen gambar sederhana akan berfungsi dengan baik.
- Ini hanya satu langkah. Anda dapat menggunakan offset yang Anda temukan dalam satu langkah dan meningkatkannya di langkah kedua, mungkin dengan jendela pencarian yang lebih kecil atau ukuran blok yang lebih kecil
- Saya telah membaca artikel di mana mereka melakukan ini tanpa blok sama sekali, tetapi mengoptimalkan offset per piksel.
- Coba berbagai fungsi kelancaran