मैं वर्तमान में बाहरी ट्रैकिंग सिस्टम का उपयोग कर वेबकैम-आधारित एआर के लिए एक वैकल्पिक विधि को लागू करने की कोशिश कर रहा हूं। मेरे पास पर्यावरण वातावरण में सब कुछ है जो बाह्य अंशांकन के लिए सहेजा गया है। मैंने cv::solvePnP()
का उपयोग करने का निर्णय लिया क्योंकि यह माना जाता है कि मैं वास्तव में काफी चाहता हूं, लेकिन दो सप्ताह बाद मैं अपने बालों को काम करने की कोशिश कर रहा हूं। नीचे एक आरेख मेरी कॉन्फ़िगरेशन दिखाता है। सी 1 मेरा कैमरा है, सी 2 ऑप्टिकल ट्रैकर है जिसका उपयोग मैं कर रहा हूं, एम कैमरे से जुड़ा हुआ ट्रैक मार्कर है, और सी चेकरबोर्ड है।सीवी के साथ बाह्य अंशांकन :: SolvePnP
यह मैं अपने छवि पिक्सेल में पास खड़ा के रूप में cv::findChessboardCorners()
के साथ प्राप्त निर्देशांक। दुनिया के अंक कैमरे सी 1 से चिपकने वाले ट्रैक किए गए मार्कर एम के संदर्भ में अधिग्रहित किए जाते हैं (इस प्रकार बाह्य रूप से इस मार्कर के फ्रेम से कैमरा उत्पत्ति में परिवर्तन होता है)। मैंने स्थानीय मिनीमा की संभावना को कम करने के लिए 50 अंकों तक डेटा सेट के साथ इसका परीक्षण किया है, लेकिन अभी के लिए मैं केवल चार 2 डी/3 डी पॉइंट जोड़े के साथ परीक्षण कर रहा हूं। परिणामी बाह्य Ive से प्राप्त होता है और cv::solvePnP()
से लौटाया गया टीवीसी दोनों ग्राउंड सच्चाई बाहरी दोनों के सापेक्ष अनुवाद और घूर्णन के संदर्भ में व्यापक रूप से बंद होता है, जिसे मैंने मैन्युअल रूप से बनाया है और मूल दृश्य विश्लेषण (अनुवाद का मतलब है कि कैमरे के दौरान 1100 मिमी दूरी का मतलब है लगभग 10 मिमी दूर है)।
प्रारंभ में मैंने सोचा था कि मुद्दा यह था कि मेरे बोर्ड की स्थिति को निर्धारित करने में मुझे कुछ अस्पष्टताएं थीं, लेकिन अब मैं काफी हद तक निश्चित हूं कि ऐसा नहीं है। गणित बहुत सरल लगता है और सिस्टम को स्थापित करने के मेरे सभी कामों के बाद, अनिवार्य रूप से एक-लाइनर जो पकड़ा जाता है, उस पर पकड़ा जाना एक बड़ी निराशा है। मैं ईमानदारी से विकल्पों से बाहर चला रहा हूं, इसलिए यदि कोई मदद कर सकता है तो मैं आपके कर्ज में बहुत अधिक होगा। मेरा टेस्ट कोड नीचे पोस्ट किया गया है और मेरे कार्यान्वयन के समान कुछ प्रतिपादन कॉल के समान है। जमीनी सच्चाई बाह्य मेरे पास है कि मेरे कार्यक्रम के साथ काम करता है इस प्रकार है (मूल रूप से एक धुरी के चारों ओर एक शुद्ध रोटेशन और एक छोटे से अनुवाद):
1 0 0 29
0 .77 -.64 32.06
0 .64 .77 -39.86
0 0 0 1
धन्यवाद!
#include <opencv2\opencv.hpp>
#include <opencv2\highgui\highgui.hpp>
int main()
{
int imageSize = 4;
int markupsSize = 4;
std::vector<cv::Point2d> imagePoints;
std::vector<cv::Point3d> markupsPoints;
double tempImage[3], tempMarkups[3]; // Temp variables or iterative data construction
cv::Mat CamMat = (cv::Mat_<double>(3,3) << (566.07469648019332), 0, 318.20416967732666,
0, (565.68051204299513), -254.95231997403764, 0, 0, 1);
cv::Mat DistMat = (cv::Mat_<double>(5,1) << -1.1310542849120900e-001, 4.5797249991542077e-001,
7.8356355644908070e-003, 3.7617039978623504e-003, -1.2734302146228518e+000);
cv::Mat rvec = cv::Mat::zeros(3,1, cv::DataType<double>::type);
cv::Mat tvec = cv::Mat::zeros(3,1,cv::DataType<double>::type);
cv::Mat R;
cv::Mat extrinsic = cv::Mat::eye(4, 4, CV_64F);
// Escape if markup lists aren't equally sized
if(imageSize != markupsSize)
{
//TODO: Replace with try, throw error code, and catch in qSlicerLocalizationModuleWidget
return 0;
}
// Four principal chessboard corners only
imagePoints.push_back(cv::Point2d(368.906, 248.123));
imagePoints.push_back(cv::Point2d(156.583, 252.414));
imagePoints.push_back(cv::Point2d(364.808, 132.384));
imagePoints.push_back(cv::Point2d(156.692, 128.289));
markupsPoints.push_back(cv::Point3d(495.115, 39.106, 93.79));
markupsPoints.push_back(cv::Point3d(463.143, -86.286, -51.178));
markupsPoints.push_back(cv::Point3d(500.236, 121.988, 24.056));
markupsPoints.push_back(cv::Point3d(471.276, -3.23, -127.809));
// Larger data set
/*imagePoints.push_back(cv::Point2d(482.066, 233.778));
imagePoints.push_back(cv::Point2d(448.024, 232.038));
imagePoints.push_back(cv::Point2d(413.895, 230.785));
imagePoints.push_back(cv::Point2d(380.653, 229.242));
imagePoints.push_back(cv::Point2d(347.983, 227.785));
imagePoints.push_back(cv::Point2d(316.103, 225.977));
imagePoints.push_back(cv::Point2d(284.02, 224.905));
imagePoints.push_back(cv::Point2d(252.929, 223.611));
imagePoints.push_back(cv::Point2d(483.41, 200.527));
imagePoints.push_back(cv::Point2d(449.456, 199.406));
imagePoints.push_back(cv::Point2d(415.843, 197.849));
imagePoints.push_back(cv::Point2d(382.59, 196.763));
imagePoints.push_back(cv::Point2d(350.094, 195.616));
imagePoints.push_back(cv::Point2d(317.922, 194.027));
imagePoints.push_back(cv::Point2d(286.922, 192.814));
imagePoints.push_back(cv::Point2d(256.006, 192.022));
imagePoints.push_back(cv::Point2d(484.292, 167.816));
imagePoints.push_back(cv::Point2d(450.678, 166.982));
imagePoints.push_back(cv::Point2d(417.377, 165.961));
markupsPoints.push_back(cv::Point3d(457.132, 59.822, 89.247));
markupsPoints.push_back(cv::Point3d(451.634, 42.015, 69.719));
markupsPoints.push_back(cv::Point3d(447.06, 22.927, 48.635));
markupsPoints.push_back(cv::Point3d(442.424, 4.454, 28.659));
markupsPoints.push_back(cv::Point3d(437.621, -14.395, 7.495));
markupsPoints.push_back(cv::Point3d(433.386, -33.034, -12.009));
markupsPoints.push_back(cv::Point3d(429.227, -51.001, -32.269));
markupsPoints.push_back(cv::Point3d(424.291, -70.266, -52.667));
markupsPoints.push_back(cv::Point3d(460.300, 79.769, 69.948));
markupsPoints.push_back(cv::Point3d(455.020, 61.379, 49.306));
markupsPoints.push_back(cv::Point3d(450.501, 43.288, 30.250));
markupsPoints.push_back(cv::Point3d(446.062, 24.572, 8.713));
markupsPoints.push_back(cv::Point3d(441.346, 5.823, -10.997));
markupsPoints.push_back(cv::Point3d(436.670, -13.135, -31.428));
markupsPoints.push_back(cv::Point3d(432.367, -31.428, -51.785));
markupsPoints.push_back(cv::Point3d(427.745, -50.016, -72.519));
markupsPoints.push_back(cv::Point3d(464.824, 101.129, 52.251));
markupsPoints.push_back(cv::Point3d(458.628, 81.864, 30.810));
markupsPoints.push_back(cv::Point3d(454.120, 63.546, 10.458)); */
// Calculate camera pose
cv::solvePnP(cv::Mat(markupsPoints), cv::Mat(imagePoints), CamMat, DistMat, rvec, tvec);
cv::Rodrigues(rvec, R);
// Invert results of Rodrigues by transposing rotation matrix and calculating inverted tvec
R = R.t();
tvec = -R * tvec; // translation of inverse
std::cout << "Tvec = " << std::endl << tvec << std::endl;
// Copy R and tvec into the extrinsic matrix
extrinsic(cv::Range(0,3), cv::Range(0,3)) = R * 1;
extrinsic(cv::Range(0,3), cv::Range(3,4)) = tvec * 1;
// Fill last row of homogeneous transform (0,0,0,1)
double *p = extrinsic.ptr<double>(3);
p[0] = p[1] = p[2] = 0; p[3] = 1;
std::cout << "Extrinsic = " << std::endl << extrinsic << std::endl << std::endl;
std::cout << "Extrinsic (inv) = " << std::endl << extrinsic.inv() << std::endl;
std::cin >> tempImage[0];
return 0;
}
संपादित करें 1: मैं ची जू की विधि का उपयोग पिक्सेल मूल्यों को सामान्य करने की कोशिश की (xn = (एक्स-CX)/च, yn = (y-cy)/च)। कोई भाग्य नहीं :(
संपादित करें 2: ऐसा लगता है कि लगभग हर कोई जो समाधान पीएनपी का उपयोग करता है, वह एक विधि का उपयोग करता है जहां वे चेकरबोर्ड कोनों को उनके विश्व फ्रेम और मूल के लिए वैक्टर के रूप में चिह्नित करते हैं, मैं अपने ट्रैकर को पंजीकृत करने का प्रयास करने जा रहा हूं चेकरबोर्ड। यदि यह अपेक्षित काम करता है, तो पहला समन्वय I चिह्न लगभग < 0,0> होगा। समाधान पीएनपी से परिणामस्वरूप परिवर्तन को दुनिया-से-कैमरा-मार्कर परिवर्तन के विपरीत से गुणा किया जाएगा, जिसके परिणामस्वरूप (उम्मीद है कि) बाह्य मैट्रिक्स।
संपादित 3: मैंने चरण 2 में वर्णित चरणों का प्रदर्शन किया। चेकरबोर्ड पर एक समन्वय प्रणाली स्थापित करने के बाद, मैंने चेकरबोर्ड स्पेस से विश्व अंतरिक्ष में परिवर्तन सीटीडब्ल्यू की गणना की और इसे मेरे प्रतिपादन वातावरण में सत्यापित किया मैं टी मुर्गी ने कैमरे की जगह से चेकरबोर्ड स्पेस में परिवर्तन का प्रतिनिधित्व करने वाले बाह्य एमटीसी की गणना की। कैमरे मार्कर ट्रांसफॉर्म डब्ल्यूटीआर को ट्रैकिंग सिस्टम से अधिग्रहित किया गया था। अंत में, मैं रूपांतरण के सभी ले गए और उन्हें गुणा के रूप में मेरे परिवर्तन सभी तरह कैमरा मूल से कैमरा मार्कर को स्थानांतरित करने के लिए इस प्रकार है:
mTc*cTw*wTr
लो और निहारना यह ठीक उसी परिणाम दे दी है। मैं जो भी गलत कर रहा हूं उसके किसी भी संकेत के लिए मैं यहां मर रहा हूं। अगर किसी के पास कोई सुराग है, तो मैं आपकी मदद करने के लिए विनती करता हूं।
संपादित 4: आज मुझे एहसास हुआ कि मैंने अपने चेकरबोर्ड अक्ष को इस तरह से कॉन्फ़िगर किया है कि वे बाएं हाथ की समन्वय प्रणाली में थे। चूंकि ओपनसीवी मानक दाएं हाथ के फॉर्म का उपयोग करके संचालित होता है, इसलिए मैंने दाएं हाथ के फैशन में कॉन्फ़िगर किए गए मेरे चेकरबोर्ड फ्रेम अक्षों के साथ परीक्षणों का पुनः प्रयास करने का निर्णय लिया। जबकि परिणाम समान थे, मैंने देखा कि विश्व-से-चेकरबोर्ड परिवर्तन अब एक गैर-मानक परिवर्तन प्रारूप था, यानी 3x3 रोटेशन मैट्रिक्स अब विकर्ण के आसपास लगभग सममित नहीं था जैसा कि होना चाहिए। यह इंगित करता है कि मेरी ट्रैकिंग प्रणाली एक दाएं हाथ समन्वय प्रणाली का उपयोग नहीं कर रही है (यदि उन्होंने दस्तावेज किया था तो बहुत अच्छा होता। या कुछ भी, उस मामले के लिए)। हालांकि मुझे यकीन नहीं है कि इसे कैसे हल किया जाए, मुझे यकीन है कि यह इस मुद्दे का हिस्सा है। मैं इस पर हमला रखूंगा और उम्मीद करता हूं कि यहां कोई जानता है कि क्या करना है। मैंने ओपनसीवी बोर्डों पर Eduardo द्वारा मुझे प्रदान किया गया एक चित्र भी जोड़ा है। धन्यवाद Eduardo!
* या कुछ भी, उस मामले के लिए * +1 – null