जैसा कि मैंने टिप्पणियों में कहा है, चिकित्सा छवि पंजीकरण बहुत सारे शोध उपलब्ध हैं, और मैं विशेषज्ञ नहीं हूं। मैंने जो पढ़ा है, उसमें से जो मूल विचार आमतौर पर इस्तेमाल किया जाता है, वह है दो मैपिंग (आपके मामले में एक इमेज और उसकी मिरर इमेज) के बीच मैपिंग को परिभाषित करना, फिर स्मूथनेस के लिए एनर्जी टर्म्स को परिभाषित करना और अगर मैपिंग लागू होती है तो इमेज समानता के लिए। मानक (या कभी-कभी एप्लिकेशन-विशिष्ट) अनुकूलन तकनीकों का उपयोग करके इस मानचित्रण का अनुकूलन करें।
मैंने इसे प्रदर्शित करने के लिए 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]]]
दुख की बात है कि इस डेटा का उपयोग करना सीधे तौर पर जितना मैंने सोचा था उससे अधिक कठिन था, इसलिए मैंने इसके बजाय एक 2 के क्रम सन्निकटन का उपयोग किया:
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]];
सौभाग्य से, विवश अनुकूलन में निर्मित है गणितज्ञ:
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
सापेक्ष वजन चिकनाई ऊर्जा छवि मैच ऊर्जा अवधि के संबंध में प्राप्त करता है। ये विभिन्न भारों के परिणाम हैं:
संभावित सुधार:
- जैसा मैंने कहा, पहले एक कठोर पंजीकरण करें। एक सफेद पृष्ठभूमि के साथ, सरल छवि क्षण-आधारित पंजीकरण ठीक काम करना चाहिए।
- यह केवल एक कदम है। आप एक चरण में मिलने वाले ऑफसेट का उपयोग कर सकते हैं और उन्हें दूसरे चरण में सुधार सकते हैं, शायद एक छोटी खोज विंडो या छोटे ब्लॉक आकार के साथ
- मैंने उन लेखों को पढ़ा है जहाँ वे बिना ब्लॉक के ऐसा करते हैं, लेकिन एक ऑफसेट प्रति पिक्सेल का अनुकूलन करते हैं।
- विभिन्न चिकनाई कार्यों का प्रयास करें