2020
2121namespace xpcf = org::bcom::xpcf;
2222
23- // test optimization code implemented by yzhou
23+ // Optimizations made by yzhou. The optimization is based on the assumption that a high performance GPU is available
24+ // If you want to unactivate these optimizations you can comment the following line
2425#define OPTIM_ON
2526
2627XPCF_DEFINE_FACTORY_CREATE_INSTANCE (SolAR::MODULES::OPENCV::SolARDescriptorMatcherGeometricOpencv)
@@ -45,17 +46,10 @@ SolARDescriptorMatcherGeometricOpencv::~SolARDescriptorMatcherGeometricOpencv()
4546
4647xpcf::XPCFErrorCode SolARDescriptorMatcherGeometricOpencv::onConfigured ()
4748{
48- #ifdef OPTIM_ON
49+ #if defined(WITHCUDA) && defined( OPTIM_ON)
4950 LOG_DEBUG (" SolARDescriptorMatcherGeometricOpencv onConfigured" );
50- #ifdef WITHCUDA
5151 m_matcher = cv::cuda::DescriptorMatcher::createBFMatcher (cv::NORM_L2);
52- #else
53- if (SolAROpenCVHelper::createMatcher (m_type, m_matcher) != FrameworkReturnCode::_SUCCESS) {
54- LOG_ERROR (" Descriptor matcher type {} is not supported" , m_type);
55- return xpcf::XPCFErrorCode::_FAIL;
56- }
57- #endif // WITHCUDA
58- #endif
52+ #endif
5953 return xpcf::XPCFErrorCode::_SUCCESS;
6054}
6155
@@ -79,6 +73,7 @@ FrameworkReturnCode SolARDescriptorMatcherGeometricOpencv::match(const SRef<SolA
7973 }
8074 // calculate fundametal matrix
8175#ifdef OPTIM_ON
76+ // avoid inverting pose matrix
8277 Transform3Df pose1Inv;
8378 for (int i = 0 ; i < 3 ; i++)
8479 for (int j = 0 ; j < 3 ; j++)
@@ -102,6 +97,7 @@ FrameworkReturnCode SolARDescriptorMatcherGeometricOpencv::match(const SRef<SolA
10297 cv::Mat K1 (3 , 3 , CV_32FC1, (void *)camParams1.intrinsic .data ());
10398 cv::Mat K2 (3 , 3 , CV_32FC1, (void *)camParams2.intrinsic .data ());
10499#ifdef OPTIM_ON
100+ // avoid inverting intrinsic matrix
105101 cv::Mat K1tInv = cv::Mat::zeros (3 , 3 , CV_32FC1);
106102 K1tInv.at <float >(0 , 0 ) = 1 .f / K1.at <float >(0 , 0 );
107103 K1tInv.at <float >(1 , 1 ) = 1 .f / K1.at <float >(1 , 1 );
@@ -147,47 +143,48 @@ FrameworkReturnCode SolARDescriptorMatcherGeometricOpencv::match(const SRef<SolA
147143
148144 // convert frame descriptor to opencv's descriptor
149145 uint32_t type_conversion = SolAR::MODULES::OPENCV::SolAROpenCVHelper::deduceOpenDescriptorCVType (descriptors1->getDescriptorDataType ());
150- # ifdef OPTIM_ON
146+ // take into account of mask for both descriptors 1 & 2
151147 cv::Mat cvDescriptor1 (indices1.size (), descriptors1->getNbElements (), type_conversion);
152- uchar* buf_in = (uchar*)descriptors1->data ();
153- uchar* buf_out = cvDescriptor1.data ;
154- uint32_t num_elements = static_cast <uint32_t >(descriptors1->getNbElements ());
155- for (auto i = 0 ; i < indices1.size (); i++) {
156- std::memcpy (buf_out, buf_in + num_elements * indices1[i], num_elements);
157- buf_out += num_elements;
148+ if (mask1.size () == 0 ) {
149+ cvDescriptor1.data = (uchar*)descriptors1->data ();
158150 }
159- cv::Mat cvDescriptor2 (indices2.size (), descriptors2->getNbElements (), type_conversion);
160- buf_in = (uchar*)descriptors2->data ();
161- buf_out = cvDescriptor2.data ;
162- num_elements = static_cast <uint32_t >(descriptors2->getNbElements ());
163- for (auto i = 0 ; i < indices2.size (); i++) {
164- std::memcpy (buf_out, buf_in + num_elements * indices2[i], num_elements);
165- buf_out += num_elements;
151+ else {
152+ uchar* buf_in = (uchar*)descriptors1->data ();
153+ uchar* buf_out = cvDescriptor1.data ;
154+ uint32_t num_elements = static_cast <uint32_t >(descriptors1->getNbElements ());
155+ for (auto i = 0 ; i < indices1.size (); i++) {
156+ std::memcpy (buf_out, buf_in + num_elements * indices1[i], num_elements);
157+ buf_out += num_elements;
158+ }
166159 }
167- #else
168- cv::Mat cvDescriptor1 (descriptors1->getNbDescriptors (), descriptors1->getNbElements (), type_conversion);
169- cvDescriptor1.data = (uchar*)descriptors1->data ();
170- cv::Mat cvDescriptor2 (descriptors2->getNbDescriptors (), descriptors2->getNbElements (), type_conversion);
171- cvDescriptor2.data = (uchar*)descriptors2->data ();
172- #endif
173160
161+ cv::Mat cvDescriptor2 (indices2.size (), descriptors2->getNbElements (), type_conversion);
162+ if (mask2.size () == 0 ) {
163+ cvDescriptor2.data = (uchar*)descriptors2->data ();
164+ }
165+ else {
166+ uchar* buf_in = (uchar*)descriptors2->data ();
167+ uchar* buf_out = cvDescriptor2.data ;
168+ uint32_t num_elements = static_cast <uint32_t >(descriptors2->getNbElements ());
169+ for (auto i = 0 ; i < indices2.size (); i++) {
170+ std::memcpy (buf_out, buf_in + num_elements * indices2[i], num_elements);
171+ buf_out += num_elements;
172+ }
173+ }
174174
175- #ifdef OPTIM_ON
176175 // perform descriptor matching first on GPU using Cuda if SolARModuleOpenCVCuda
176+ #if defined(WITHCUDA) && defined(OPTIM_ON)
177+ cv::cuda::GpuMat cvDescriptor1Gpu, cvDescriptor2Gpu;
177178 std::vector< std::vector<cv::DMatch> > nn_matches;
178- #ifdef WITHCUDA
179179 if (descriptors1->getDescriptorDataType () != DescriptorDataType::TYPE_32F) // convert to float because cuda descriptor match only supports float type
180180 cvDescriptor1.convertTo (cvDescriptor1, CV_32F);
181181 if (descriptors2->getDescriptorDataType () != DescriptorDataType::TYPE_32F)
182182 cvDescriptor2.convertTo (cvDescriptor2, CV_32F);
183- cv::cuda::GpuMat cvDescriptor1Gpu, cvDescriptor2Gpu;
183+
184184 cvDescriptor1Gpu.upload (cvDescriptor1);
185185 cvDescriptor2Gpu.upload (cvDescriptor2);
186186 m_matcher->knnMatch (cvDescriptor1Gpu, cvDescriptor2Gpu, nn_matches, 2 );
187- #else
188- m_matcher->knnMatch (cvDescriptor1, cvDescriptor2, nn_matches, 2 );
189- #endif
190-
187+
191188 // filter the matches by three conditions (best distance, 2nd best distance and epipolar constraint)
192189 std::vector<bool > checkMatches (indices2.size (), true );
193190 float acceptedDist = m_paddingRatio * camParams2.resolution .width ;
@@ -215,19 +212,19 @@ FrameworkReturnCode SolARDescriptorMatcherGeometricOpencv::match(const SRef<SolA
215212 }
216213#else
217214 // first apply epipolar constraint then apply descriptor matching
218- std::vector<bool > checkMatches (undistortedKeypoints2 .size (), true );
215+ std::vector<bool > checkMatches (indices2 .size (), true );
219216 float acceptedDist = m_paddingRatio * camParams2.resolution .width ;
220217 for (int i = 0 ; i < indices1.size (); i++) {
221- const cv::Mat cvDes1 = cvDescriptor1.row (indices1[i] );
218+ const cv::Mat cvDes1 = cvDescriptor1.row (i );
222219 float bestDist = std::numeric_limits<float >::max ();
223220 float bestDist2 = std::numeric_limits<float >::max ();
224221 int bestIdx = -1 ;
225222 cv::Point3f l = lines2[i];
226223 float lxyz_norm = std::sqrt (l.x * l.x + l.y * l.y );
227-
228- for (int j = 0 ; j < undistortedKeypoints2 .size (); j++) {
229- float x = undistortedKeypoints2[j ].getX ();
230- float y = undistortedKeypoints2[j ].getY ();
224+
225+ for (int j = 0 ; j < indices2 .size (); j++) {
226+ float x = undistortedKeypoints2[indices2[j] ].getX ();
227+ float y = undistortedKeypoints2[indices2[j] ].getY ();
231228 float disPointLine = std::abs (x * l.x + y * l.y + l.z ) / lxyz_norm;
232229 if (disPointLine < acceptedDist) {
233230 float dist = cv::norm (cvDes1, cvDescriptor2.row (j), cv::NORM_L2);
@@ -244,11 +241,11 @@ FrameworkReturnCode SolARDescriptorMatcherGeometricOpencv::match(const SRef<SolA
244241 }
245242 }
246243 if ((bestIdx != -1 ) && (bestDist < m_matchingDistanceMax) && (bestDist < m_distanceRatio * bestDist2) && (checkMatches[bestIdx])) {
247- matches.push_back (DescriptorMatch (indices1[i], bestIdx, bestDist));
244+ matches.push_back (DescriptorMatch (indices1[i], indices2[ bestIdx] , bestDist));
248245 checkMatches[bestIdx] = false ;
249246 }
250247 }
251- #endif
248+ #endif
252249 return FrameworkReturnCode::_SUCCESS;
253250}
254251
0 commit comments