কোনও খাবারের জারে লেবেলের চিত্র কীভাবে সমতল করবেন?


40

আমি খাবারের জারে লেবেলের ছবি তুলতে চাই এবং লেবেলটি সমতল হওয়ায় এগুলি রূপান্তর করতে সক্ষম হব, ডান এবং বাম পাশের চিত্রটির কেন্দ্রবিন্দুতে থাকা অবস্থায়ও পুনরায় আকার দিন।

আদর্শভাবে, আমি প্রান্তগুলি সন্ধান করতে এবং সংশোধনটি প্রয়োগ করতে লেবেল এবং পটভূমির মধ্যে বিপরীতে ব্যবহার করতে চাই। অন্যথায়, আমি কোনওভাবে চিত্রটির কোণ এবং দিকগুলি সনাক্ত করতে ব্যবহারকারীকে বলতে পারি।


আমি এমন একটি চিত্র নেওয়ার জন্য সাধারণ কৌশল এবং অ্যালগরিদমগুলির সন্ধান করছি যা স্ফুলিভাবে আঁকা (আমার ক্ষেত্রে নলাকার) এবং চিত্রটি সমতল করতে পারে। বর্তমানে কোনও জার বা বোতল দিয়ে আবৃত একটি লেবেলের চিত্রটিতে বৈশিষ্ট্য এবং পাঠ্য থাকবে যা চিত্রের ডান বা বাম দিকে ফিরে আসতেই সঙ্কুচিত হবে। এছাড়াও লাইনগুলি যে লেবেলের প্রান্তটি বোঝায়, কেবলমাত্র চিত্রের কেন্দ্রে সমান্তরাল হবে এবং লেবেলের ডান এবং বাম চরম অংশে একে অপরের দিকে আকস্মিক হবে।

চিত্রটি হেরফের করার পরে, আমি প্রায় নিখুঁত আয়তক্ষেত্রটি রেখে যেতে চাই যেখানে পাঠ্য এবং বৈশিষ্ট্যগুলি সমান আকারযুক্ত, যেন আমি লেবেলের কোনও ছবি যখন জার বা বোতলটিতে না থাকি।

এছাড়াও, আমি এটি চাই যদি প্রযুক্তিটি যথাযথ সংশোধন প্রয়োগ করার জন্য লেবেলের প্রান্তগুলি স্বয়ংক্রিয়ভাবে সনাক্ত করতে পারে। অন্যথায় আমি আমার ব্যবহারকারীকে লেবেলের সীমানা নির্দেশ করতে বলব।

আমি ইতিমধ্যে গুগলেড করেছি এবং এর মতো নিবন্ধগুলি পেয়েছি: বাঁকা ডকুমেন্টগুলি সমতল করা , তবে আমি কিছুটা সহজতর কিছু সন্ধান করছি, কারণ আমার প্রয়োজনগুলি একটি সরল বাঁকানো লেবেলগুলির জন্য।


নিকির কাছে এটি রয়েছে যা একটি সর্ব-পরিবেশন সমাধান হিসাবে দেখা যাচ্ছে। এটি অনেক সহজ হয়ে যায়, যদিও আপনি যদি জানেন যে ক্যামেরাটি সবসময় জারের কাছে "স্কয়ার" থাকে তবে কোনও বিভ্রান্তিকর পটভূমি নেই। তারপরে আপনি জারের প্রান্তগুলি সন্ধান করুন এবং অতিরিক্ত তত্পরতা ছাড়াই সরল ত্রিকোনমিতি (আরকসাইন?) রূপান্তরটি প্রয়োগ করুন। ছবিটি একবার সমতল হয়ে গেলে আপনি নিজেই লেবেলটি আলাদা করতে পারবেন।
ড্যানিয়েল আর হিক্স

@ ড্যানিয়েল এটি আমি এখানে করেছি । আদর্শভাবে কোনওটি পুরোপুরি না-পুরোপুরি সমান্তরাল প্রক্ষেপণটিকেও বিবেচনা করবে, কিন্তু আমি তা করি নি।
কাজ Szabolcs

কাজ খুব ভাল। কিন্তু কোডটি আমার সিস্টেমে ত্রুটি দেখাচ্ছে। আমি মাতলাব 2017a ব্যবহার করছি এটি এর সাথে সামঞ্জস্যপূর্ণ। আপনাকে ধন্যবাদ,
সতীশ কুমার

উত্তর:


60

একটি অনুরূপ প্রশ্ন Mathematica.Stackexchange উপর জিজ্ঞাসা করা হল । আমার উত্তরটি সেখানে বিকশিত হয়েছিল এবং শেষ পর্যন্ত বেশ দীর্ঘ হয়েছে, সুতরাং আমি এখানে অ্যালগরিদম সংক্ষিপ্ত করব।

বিমূর্ত

মূল ধারণাটি হ'ল:

  1. লেবেলটি সন্ধান করুন।
  2. লেবেলের সীমানা সন্ধান করুন
  3. সিলিন্ডার স্থানাঙ্কগুলিতে চিত্রের সমন্বয়কারী ম্যাপিংটি সন্ধান করুন যাতে এটি লেবেলের উপরের সীমানা বরাবর পিক্সেলগুলিকে মানচিত করে ([কিছু] / 0), ডান সীমান্তে (1 / [কিছু]) পিক্সেল এবং আরও কিছু করতে পারে।
  4. এই ম্যাপিং ব্যবহার করে চিত্রটি রূপান্তর করুন

অ্যালগরিদম কেবল এমন চিত্রগুলির জন্য কাজ করে যেখানে:

  1. লেবেলটি পটভূমির চেয়ে উজ্জ্বল (এটি লেবেল সনাক্তকরণের জন্য প্রয়োজন)
  2. লেবেলটি আয়তক্ষেত্রাকার (এটি একটি ম্যাপিংয়ের মান পরিমাপ করতে ব্যবহৃত হয়)
  3. জারটি (প্রায়) উল্লম্ব (এটি ম্যাপিং ফাংশনটি সহজ রাখতে ব্যবহৃত হয়)
  4. জারটি নলাকার (এটি ম্যাপিংয়ের কাজটি সহজ রাখতে ব্যবহৃত হয়)

তবে, অ্যালগরিদমটি মডিউলার। অন্তত নীতিগতভাবে, আপনি নিজের লেবেল সনাক্তকরণ লিখতে পারেন যাতে অন্ধকার পটভূমির প্রয়োজন হয় না, বা আপনি নিজের মানের পরিমাপের ফাংশন লিখতে পারেন যা উপবৃত্তাকার বা অষ্টভুজ লেবেলগুলির সাথে মোকাবিলা করতে পারে।

ফলাফল

এই চিত্রগুলি সম্পূর্ণরূপে স্বয়ংক্রিয়ভাবে প্রক্রিয়া করা হয়েছিল, অর্থাৎ অ্যালগরিদম উত্স চিত্রটি গ্রহণ করে, কয়েক সেকেন্ডের জন্য কাজ করে, তারপরে ম্যাপিং (বাম) এবং অ-বিকৃত চিত্র (ডানদিকে) দেখায়:

এখানে চিত্র বর্ণনা লিখুন

এখানে চিত্র বর্ণনা লিখুন

এখানে চিত্র বর্ণনা লিখুন

এখানে চিত্র বর্ণনা লিখুন

এখানে চিত্র বর্ণনা লিখুন

এখানে চিত্র বর্ণনা লিখুন

এখানে চিত্র বর্ণনা লিখুন

পরবর্তী চিত্রগুলি অ্যালগরিদমের পরিবর্তিত সংস্করণ দিয়ে প্রক্রিয়া করা হয়েছিল, ব্যবহারকারী কি জারের বাম এবং ডান সীমানা (লেবেল নয়) বাছাই করে, কারণ সামনের শটটিতে লেবেলের বক্রতা চিত্র থেকে অনুমান করা যায় না (যেমন সম্পূর্ণ স্বয়ংক্রিয় অ্যালগরিদম এমন চিত্রগুলি ফেরত দেবে যা সামান্য বিকৃত):

এখানে চিত্র বর্ণনা লিখুন

এখানে চিত্র বর্ণনা লিখুন

বাস্তবায়ন:

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}}]}]]]]

LocatorPane

এটি বিকল্প অপ্টিমাইজেশন কোড, যেখানে কেন্দ্র এবং ব্যাসার্ধ স্পষ্টভাবে দেওয়া আছে।

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]

11
সানগ্লাসগুলি সরিয়ে দেয় ... god
শ্বরের

আপনি কি নলাকার মানচিত্রের রেফারেন্স পেয়েছেন? এবং সম্ভবত বিপরীত ম্যাপিং জন্য সমীকরণ? @ নিক-এস্টনার
ইটা
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.