Gfranq.com फोटो सेवा में क्षितिज संरेखण

Gfranq.com फ़ोटो सेवा में फ़ोटो को एक मनमाने कोण पर संरेखित करने की क्षमता है! इस कोण की गणना स्वचालित रूप से की जाती है, लेकिन यदि आवश्यक हो, तो इसे आसानी से मैन्युअल रूप से बदला जा सकता है। क्षितिज रेखा को सही माउस बटन के साथ खींचा जा सकता है, और संसाधित तस्वीर इंस्टाग्राम के विपरीत आयताकार हो सकती है। इसके अलावा, घुमाए गए चित्र में मूल छवि का आकार बनाए रखने या अधिकतम क्षेत्र को कवर करने के लिए एक विकल्प प्रदान किया जाता है।



कोई भी यह जानना चाहता है कि स्वचालित संरेखण विधि हमारे लिए कैसे काम करती है, और क्या एल्गोरिदम का उपयोग किया गया था, बिल्ली के नीचे स्वागत है।

स्वचालित क्षितिज संरेखण विधि


अधिकांश तस्वीरों के लिए स्वीकार्य स्तर पर काम करने के लिए स्वचालित क्षितिज संरेखण के लिए, इस कार्य को निम्नलिखित चरणों में विभाजित करने का निर्णय लिया गया:

  1. सीमाओं की परिभाषा।
  2. सीधी रेखाओं की परिभाषा।
  3. सबसे तीव्र रेखा की गणना।
  4. पाया रेखा और छवि के केंद्र के बीच के कोण की गणना।
  5. गणना कोण द्वारा छवि को घुमाएं।
  6. घुमाए गए छवि में अंकित अधिकतम आयत की गणना।

आगे, इन चरणों पर विस्तार से विचार किया जाएगा।

सीमा परिभाषा (कैनी ऑपरेटर)।

सीमाओं को निर्धारित करने के लिए, विषयगत और उद्देश्यपूर्ण विचार (जिसे विकिपीडिया पर पढ़ा जा सकता है) के आधार पर कैनी बॉर्डर डिटेक्टर का उपयोग करने का निर्णय लिया गया।
कैनी के एल्गोरिथ्म में निम्नलिखित चरण शामिल हैं:
  1. एक छवि को काले और सफेद में बदलें।
  2. गाऊसी छवि धुंधली।
  3. ग्रेडियरों के लिए खोजें।
  4. गैर-अधिकतम दमन और अस्पष्टता अनुरेखण।

सीधी रेखाओं की परिभाषा (हूप ट्रांसफॉर्म)।

छवि पर सीमाएं पाए जाने के बाद (चमक या अन्य असमानताओं में तेज बदलाव), सीधी रेखाओं को निकालने के लिए एक एल्गोरिथ्म लागू करना संभव है, क्योंकि क्षितिज आमतौर पर एक सीधी या लगभग सीधी रेखाओं (संभवतः शोर के साथ) की तरह दिखता है। दिए गए एल्गोरिथम के रूप में हाफ ट्रांसफॉर्म को चुना गया था। हालांकि, यह परिवर्तन बहुत बड़ी संख्या में रेखाएँ लौटा सकता है, इसके अलावा, यह एक छवि (मैट्रिक्स) लौटाता है जिसमें लाइनों के कोण क्षैतिज रूप से मापा जाता है, और लंबवत - केंद्र से लाइन की दूरी, जो आगे के चरणों के लिए असुविधाजनक है। इन समस्याओं को हल करने के लिए, ध्रुवीय निर्देशांक से आयताकार तक लाइनों को परिवर्तित करने का कार्य लिखा गया था:

आयताकार निर्देशांक में रेखाखंडों में ध्रुवीय निर्देशांक में रेखाएँ परिवर्तित करें
private static WeightedLine HoughLineToTwoPointLine(double theta, short radius, double intensity, int width, int height) { int r = radius; double t = theta; if (r < 0) { t += 180; r = -r; } t = (t / 180) * Math.PI; int w2 = width / 2; int h2 = height / 2; double x0 = 0, x1 = 0, y0 = 0, y1 = 0; if (theta != 0) { x0 = -w2; x1 = w2; double sint = Math.Sin(t); double cost = Math.Cos(t); y0 = (-cost * x0 + r) / sint; y1 = (-cost * x1 + r) / sint; } else { x0 = radius; x1 = radius; y0 = h2; y1 = -h2; } return new WeightedLine(x0 + w2, h2 - y0, x1 + w2, h2 - y1, intensity); } 


परिणामी कोण की गणना

चौड़ाई और ऊंचाई आयामों और निर्देशांक X1, y1, x2, y2 और क्षैतिज रेखा (दूसरे शब्दों में, जिस कोण से छवि को घुमाया जाना चाहिए, ताकि कोण को घुमाया जाए ताकि क्षितिज रेखा X1, y1, x2, y2, y2, x2, y2) के साथ छवि के केंद्र से गुजरने वाले कोणों के बीच के कोण की गणना का कार्य हो सके। क्षैतिज रूप से संरेखित):

परिणाम कोण गणना विधि कोड
 public static double CalculateAngle(int width, int height, double x1, double y1, double x2, double y2) { double dx = x2 - x1; double dy = y2 - y1; double x3 = width / 2; double y3 = height / 2; double r = dx * dx + dy * dy; double nx = (dx * (x3 * dx - dy * y1) + dy * (dx * y3 + x1 * dy)) / r - x3; double ny = (dx * (y1 * dx - x1 * dy) + dy * (dx * x3 + dy * y3)) / r - y3; double result = Math.Atan2(ny, nx) + Math.PI / 2; if (result > Math.PI) result = result - Math.PI * 2; return result; } 


यह ध्यान देने योग्य है कि यदि परिकलित कोण एक निश्चित सेट रोटेशन मान से अधिक है (हमारे मामले में यह 45 ° है), तो स्वचालित रोटेशन प्रदर्शन नहीं किया जाएगा।

परिणामी उत्कीर्ण आयत की गणना

छवि को घुमाने के लिए कोण की गणना के बाद, घुमाए गए छवि में अंकित अधिकतम आयत के आयामों की गणना करना आवश्यक है। यह ध्यान देने योग्य है कि यह आयत या तो आनुपातिक हो सकती है (इस मामले में, मूल छवि का आकार संरक्षित है, अर्थात, अंकित छवि का हिस्सा अपने मूल आकार तक फैला हुआ है), या असंतुष्ट, घुमाए गए छवि में पूरे अधिकतम क्षेत्र को कवर करता है।

इस समस्या को हल करने के लिए, स्टैकओवरफ़्लो पर एक संबंधित प्रश्न पाया गया था और उत्तरों में से एक को निम्नलिखित कोड में संशोधित किया गया था: स्टैकओवरफ़्लो के लिए लिंक

उपरोक्त चरणों को बेहतर ढंग से समझने के लिए, मैंने प्रक्रिया का एक ग्राफिक चित्रण तैयार किया:
छवि

तकनीकी विवरण


हमारी परियोजना इस तरह से डिज़ाइन की गई है कि कुछ मॉड्यूल का कोड C # में लिखा गया है, जो पिछले लेखों में से एक में वर्णित .NET और जावास्क्रिप्ट के तहत दोनों को संकलित करता है। तदनुसार, इस मॉड्यूल का कोड C # में भी लिखा गया था। ऐसा करने के लिए, हमें दो-आयामी लोगों के बजाय एक-आयामी सरणियों का उपयोग करना पड़ा, और कुछ अन्य स्क्रिप्ट # सीमाओं को भी ध्यान में रखना चाहिए।

Google Chrome में चित्र घुमाएं

दुर्भाग्यवश, Google Chrome में रूपांतरणों के दौरान सीमाओं पर छवियों को सुचारू करने की अनुपस्थिति में एक बग है (उदाहरण के लिए, घुमाव), जो स्पष्ट रूप से बाईं ओर नीचे के चित्र में दिखाया गया है, जबकि छवियां स्वयं सही ढंग से प्रक्षेपित हैं। ब्राउज़रों के अन्य आधुनिक संस्करणों (IE, फ़ायरफ़ॉक्स, सफारी, ओपेरा) में, यह बग हमारे द्वारा देखा गया था। इसलिए, हम इससे बचने का एक तरीका लेकर आए हैं: आप निम्नलिखित कोड का उपयोग करके छवि के चारों ओर एक पारदर्शी सीमा खींच सकते हैं (यानी छवि 2 पिक्सेल छोटी होगी):

 context.draw(image, 1, 1, decImageWidth - 2, decImageHeight - 2); 

इस प्रकार, सभी ब्राउज़रों (सही पर नीचे आंकड़ा) में एक चौरसाई प्रभाव प्राप्त करना संभव था।



निष्कर्ष


एल्गोरिदम में सीमाओं और Hough को निर्धारित करने के लिए गुणांक में भिन्नता से, एक स्वीकार्य गुणवत्ता और स्वचालित संरेखण की गति को प्राप्त करना संभव था, जिसे छवियों के कई उदाहरणों पर परीक्षण किया गया था। और उन छवियों में जहां विधि सही तरीके से काम नहीं करती है, कोण को दो तरीकों से आसानी से मैन्युअल रूप से तय किया जा सकता है, जैसा कि आप हमारी gfranq.com फोटो सेवा पर एक नया जोड़कर या किसी मौजूदा फोटो को संपादित करके देख सकते हैं।

मोबाइल प्लेटफ़ॉर्म ( iOS और Android ) पर, फोटो संरेखण सुविधा निकट भविष्य में दिखाई देगी।

Source: https://habr.com/ru/post/In194580/


All Articles