একটি অনুরূপ প্রশ্ন Mathematica.Stackexchange উপর জিজ্ঞাসা করা হল । আমার উত্তরটি সেখানে বিকশিত হয়েছিল এবং শেষ পর্যন্ত বেশ দীর্ঘ হয়েছে, সুতরাং আমি এখানে অ্যালগরিদম সংক্ষিপ্ত করব।
বিমূর্ত
মূল ধারণাটি হ'ল:
- লেবেলটি সন্ধান করুন।
- লেবেলের সীমানা সন্ধান করুন
- সিলিন্ডার স্থানাঙ্কগুলিতে চিত্রের সমন্বয়কারী ম্যাপিংটি সন্ধান করুন যাতে এটি লেবেলের উপরের সীমানা বরাবর পিক্সেলগুলিকে মানচিত করে ([কিছু] / 0), ডান সীমান্তে (1 / [কিছু]) পিক্সেল এবং আরও কিছু করতে পারে।
- এই ম্যাপিং ব্যবহার করে চিত্রটি রূপান্তর করুন
অ্যালগরিদম কেবল এমন চিত্রগুলির জন্য কাজ করে যেখানে:
- লেবেলটি পটভূমির চেয়ে উজ্জ্বল (এটি লেবেল সনাক্তকরণের জন্য প্রয়োজন)
- লেবেলটি আয়তক্ষেত্রাকার (এটি একটি ম্যাপিংয়ের মান পরিমাপ করতে ব্যবহৃত হয়)
- জারটি (প্রায়) উল্লম্ব (এটি ম্যাপিং ফাংশনটি সহজ রাখতে ব্যবহৃত হয়)
- জারটি নলাকার (এটি ম্যাপিংয়ের কাজটি সহজ রাখতে ব্যবহৃত হয়)
তবে, অ্যালগরিদমটি মডিউলার। অন্তত নীতিগতভাবে, আপনি নিজের লেবেল সনাক্তকরণ লিখতে পারেন যাতে অন্ধকার পটভূমির প্রয়োজন হয় না, বা আপনি নিজের মানের পরিমাপের ফাংশন লিখতে পারেন যা উপবৃত্তাকার বা অষ্টভুজ লেবেলগুলির সাথে মোকাবিলা করতে পারে।
ফলাফল
এই চিত্রগুলি সম্পূর্ণরূপে স্বয়ংক্রিয়ভাবে প্রক্রিয়া করা হয়েছিল, অর্থাৎ অ্যালগরিদম উত্স চিত্রটি গ্রহণ করে, কয়েক সেকেন্ডের জন্য কাজ করে, তারপরে ম্যাপিং (বাম) এবং অ-বিকৃত চিত্র (ডানদিকে) দেখায়:
পরবর্তী চিত্রগুলি অ্যালগরিদমের পরিবর্তিত সংস্করণ দিয়ে প্রক্রিয়া করা হয়েছিল, ব্যবহারকারী কি জারের বাম এবং ডান সীমানা (লেবেল নয়) বাছাই করে, কারণ সামনের শটটিতে লেবেলের বক্রতা চিত্র থেকে অনুমান করা যায় না (যেমন সম্পূর্ণ স্বয়ংক্রিয় অ্যালগরিদম এমন চিত্রগুলি ফেরত দেবে যা সামান্য বিকৃত):
বাস্তবায়ন:
1. লেবেলটি সন্ধান করুন
গা dark় পটভূমির সামনে লেবেলটি উজ্জ্বল, তাই বাইনারিাইজেশন ব্যবহার করে এটি সহজেই খুঁজে পেতে পারি:
src = Import["http://i.stack.imgur.com/rfNu7.png"];
binary = FillingTransform[DeleteBorderComponents[Binarize[src]]]
আমি কেবল বৃহত্তম সংযুক্ত উপাদানটি চয়ন করি এবং ধরে নিই যে এটি লেবেল:
labelMask = Image[SortBy[ComponentMeasurements[binary, {"Area", "Mask"}][[All, 2]], First][[-1, 2]]]
2. লেবেলের সীমানা সন্ধান করুন
পরবর্তী পদক্ষেপ: সাধারণ ডেরাইভেটিভ কনভোলিউশন মাস্ক ব্যবহার করে উপরের / নীচের / বাম / ডান সীমানা সন্ধান করুন:
topBorder = DeleteSmallComponents[ImageConvolve[labelMask, {{1}, {-1}}]];
bottomBorder = DeleteSmallComponents[ImageConvolve[labelMask, {{-1}, {1}}]];
leftBorder = DeleteSmallComponents[ImageConvolve[labelMask, {{1, -1}}]];
rightBorder = DeleteSmallComponents[ImageConvolve[labelMask, {{-1, 1}}]];
এটি একটি সামান্য সহায়ক ফাংশন যা এই চারটি চিত্রের মধ্যে একটিতে সমস্ত সাদা পিক্সেল সন্ধান করে এবং সূচকগুলি স্থানাঙ্কে রূপান্তরিত করে ( Position
ফেরত সূচকগুলি, এবং সূচকগুলি 1-ভিত্তিক {y, x t -uples, যেখানে y = 1 শীর্ষে থাকে চিত্রটি.কিন্তু সমস্ত চিত্র প্রক্রিয়াকরণ কার্য স্থানাঙ্কের প্রত্যাশা করে, যা 0-ভিত্তিক {x, y} -upuples, যেখানে y = 0 চিত্রের নীচে থাকে):
{w, h} = ImageDimensions[topBorder];
maskToPoints = Function[mask, {#[[2]]-1, h - #[[1]]+1} & /@ Position[ImageData[mask], 1.]];
৩. চিত্র থেকে সিলিন্ডার স্থানাঙ্কে ম্যাপিং সন্ধান করুন
এখন আমার কাছে লেবেলের শীর্ষ, নীচে, বাম, ডান সীমানার স্থানাঙ্কের পৃথক চারটি তালিকা রয়েছে। আমি চিত্রের স্থানাঙ্ক থেকে সিলিন্ডার স্থানাঙ্কগুলিতে একটি ম্যাপিং সংজ্ঞা দিই:
arcSinSeries = Normal[Series[ArcSin[\[Alpha]], {\[Alpha], 0, 10}]]
Clear[mapping];
mapping[{x_, y_}] :=
{
c1 + c2*(arcSinSeries /. \[Alpha] -> (x - cx)/r) + c3*y + c4*x*y,
top + y*height + tilt1*Sqrt[Clip[r^2 - (x - cx)^2, {0.01, \[Infinity]}]] + tilt2*y*Sqrt[Clip[r^2 - (x - cx)^2, {0.01, \[Infinity]}]]
}
এটি একটি নলাকার ম্যাপিং, যা উত্সের চিত্রটিতে এক্স / ওয়াই-স্থানাঙ্ককে নলাকার স্থানাঙ্কে মানচিত্র করে। মানচিত্রটি উচ্চতা / ব্যাসার্ধ / কেন্দ্র / দৃষ্টিকোণ / tালু জন্য 10 ডিগ্রি স্বাধীনতা আছে। আমি আর্ক সাইন আনুমানিক করতে টেলর সিরিজটি ব্যবহার করেছি, কারণ আমি সরাসরি আরকসিনের সাথে কাজ করে অপ্টিমাইজেশন পেতে পারি না। দ্যClip
কলগুলি অপ্টিমাইজেশনের সময় জটিল সংখ্যাগুলি রোধ করার জন্য আমার অ্যাড-হক প্রচেষ্টা। এখানে একটি বাণিজ্য বন্ধ রয়েছে: একদিকে, সর্বনিম্ন সম্ভাব্য বিকৃতি দিতে, ফাংশনটি যথাসম্ভব যথাযথ নলাকার ম্যাপিংয়ের কাছাকাছি হওয়া উচিত। অন্যদিকে, যদি এটি জটিল হয় তবে স্বয়ংক্রিয়ভাবে স্বাধীনতার ডিগ্রিগুলির জন্য অনুকূল মানগুলি খুঁজে পাওয়া আরও শক্ত হয়ে যায়। (গাণিতিকের সাথে ইমেজ প্রসেসিংয়ের দুর্দান্ত জিনিসটি হ'ল আপনি খুব সহজেই এইরকম গাণিতিক মডেলগুলির সাথে খেলা করতে পারেন, বিভিন্ন বিকৃতির জন্য অতিরিক্ত শর্তাদি চালু করতে পারেন এবং চূড়ান্ত ফলাফল পেতে একই অপ্টিমাইজেশন ফাংশন ব্যবহার করতে পারেন I've আমি কখনই কিছু করতে সক্ষম হইনি been যেমন ওপেনসিভি বা মতলব ব্যবহার করে But তবে আমি মতলবের জন্য প্রতীকী টুলবক্সটি কখনও চেষ্টা করিনি, সম্ভবত এটি এটিকে আরও কার্যকর করে তোলে))
এরপরে আমি একটি "ত্রুটি ফাংশন" সংজ্ঞায়িত করি যা কোনও চিত্রের গুণমান পরিমাপ করে -> সিলিন্ডার স্থানাঙ্ক ম্যাপিং। এটি সীমানা পিক্সেলের জন্য স্কোয়ার ত্রুটির যোগফল:
errorFunction =
Flatten[{
(mapping[#][[1]])^2 & /@ maskToPoints[leftBorder],
(mapping[#][[1]] - 1)^2 & /@ maskToPoints[rightBorder],
(mapping[#][[2]] - 1)^2 & /@ maskToPoints[topBorder],
(mapping[#][[2]])^2 & /@ maskToPoints[bottomBorder]
}];
এই ত্রুটি ফাংশনটি ম্যাপিংয়ের "মানের" পরিমাপ করে: এটি সর্বনিম্ন যদি বাম সীমান্তের পয়েন্টগুলি (0 / [কোনও কিছু]) ম্যাপ করা হয় তবে উপরের সীমান্তের পিক্সেলগুলিকে ([কিছু] / 0) ম্যাপ করা হয় এবং আরও ।
এখন আমি ম্যাথামেটিকাকে এই ত্রুটি ফাংশনটি হ্রাস করে এমন সহগগুলি খুঁজে পেতে বলতে পারি। আমি কয়েকটি সহগ সম্পর্কে (শিক্ষার অনুমান) তৈরি করতে পারি (উদাহরণস্বরূপ চিত্রের জারটির ব্যাসার্ধ এবং কেন্দ্র)। আমি এগুলি অপ্টিমাইজেশনের প্রাথমিক পয়েন্ট হিসাবে ব্যবহার করি:
leftMean = Mean[maskToPoints[leftBorder]][[1]];
rightMean = Mean[maskToPoints[rightBorder]][[1]];
topMean = Mean[maskToPoints[topBorder]][[2]];
bottomMean = Mean[maskToPoints[bottomBorder]][[2]];
solution =
FindMinimum[
Total[errorFunction],
{{c1, 0}, {c2, rightMean - leftMean}, {c3, 0}, {c4, 0},
{cx, (leftMean + rightMean)/2},
{top, topMean},
{r, rightMean - leftMean},
{height, bottomMean - topMean},
{tilt1, 0}, {tilt2, 0}}][[2]]
FindMinimum
ত্রুটি ফাংশন হ্রাস করে আমার ম্যাপিং ফাংশনের স্বাধীনতার 10 ডিগ্রির মানগুলি সন্ধান করে। জেনেরিক ম্যাপিং এবং এই সমাধানটি একত্রিত করুন এবং আমি এক্স / ওয়াই চিত্রের স্থানাঙ্কগুলি থেকে একটি ম্যাপিং পাই যা লেবেল অঞ্চলটি ফিট করে। আমি ম্যাথমেটিকার ContourPlot
ফাংশনটি ব্যবহার করে এই ম্যাপিংটি কল্পনা করতে পারি :
Show[src,
ContourPlot[mapping[{x, y}][[1]] /. solution, {x, 0, w}, {y, 0, h},
ContourShading -> None, ContourStyle -> Red,
Contours -> Range[0, 1, 0.1],
RegionFunction -> Function[{x, y}, 0 <= (mapping[{x, y}][[2]] /. solution) <= 1]],
ContourPlot[mapping[{x, y}][[2]] /. solution, {x, 0, w}, {y, 0, h},
ContourShading -> None, ContourStyle -> Red,
Contours -> Range[0, 1, 0.2],
RegionFunction -> Function[{x, y}, 0 <= (mapping[{x, y}][[1]] /. solution) <= 1]]]
৪. চিত্রটি রূপান্তর করুন
অবশেষে, আমি ImageForwardTransform
এই ম্যাপিং অনুসারে চিত্রটি বিকৃত করতে গণিতের ফাংশনটি ব্যবহার করি :
ImageForwardTransformation[src, mapping[#] /. solution &, {400, 300}, DataRange -> Full, PlotRange -> {{0, 1}, {0, 1}}]
উপরোক্ত ফলাফল হিসাবে এটি ফলাফল দেয়।
ম্যানুয়ালি সহকারী সংস্করণ
উপরের অ্যালগরিদম পুরো-স্বয়ংক্রিয়। কোন সমন্বয় প্রয়োজন। ছবিটি উপরের বা নীচে থেকে নেওয়া যায় ততক্ষণ পর্যন্ত এটি যুক্তিসঙ্গতভাবে কাজ করে। তবে এটি যদি সামনের শট হয় তবে জারের ব্যাসার্ধটি লেবেলের আকার থেকে অনুমান করা যায় না। এই ক্ষেত্রে আমি যদি ব্যবহারকারীকে নিজেই বয়ামের বাম / ডান সীমানা ম্যানুয়ালি প্রবেশ করতে দিয়ে এবং ম্যাপিংয়ে স্বতন্ত্রভাবে ডিগ্রি স্বাধীনভাবে সেট করতে দেয় তবে আমি আরও ভাল ফলাফল পেয়েছি।
এই কোডটি ব্যবহারকারীকে বাম / ডান সীমানা নির্বাচন করতে দেয়:
LocatorPane[Dynamic[{{xLeft, y1}, {xRight, y2}}],
Dynamic[Show[src,
Graphics[{Red, Line[{{xLeft, 0}, {xLeft, h}}],
Line[{{xRight, 0}, {xRight, h}}]}]]]]
এটি বিকল্প অপ্টিমাইজেশন কোড, যেখানে কেন্দ্র এবং ব্যাসার্ধ স্পষ্টভাবে দেওয়া আছে।
manualAdjustments = {cx -> (xLeft + xRight)/2, r -> (xRight - xLeft)/2};
solution =
FindMinimum[
Total[minimize /. manualAdjustments],
{{c1, 0}, {c2, rightMean - leftMean}, {c3, 0}, {c4, 0},
{top, topMean},
{height, bottomMean - topMean},
{tilt1, 0}, {tilt2, 0}}][[2]]
solution = Join[solution, manualAdjustments]