rapid: make correspondencies explicit for simpler data handling

pull/2572/head
Pavel Rojtberg 5 years ago
parent 522a062cad
commit 00fe2ed971
  1. 25
      modules/rapid/include/opencv2/rapid.hpp
  2. 2
      modules/rapid/samples/track_marker.py
  3. 109
      modules/rapid/src/rapid.cpp

@ -24,12 +24,12 @@ namespace rapid
/** /**
* Debug draw markers of matched correspondences onto a lineBundle * Debug draw markers of matched correspondences onto a lineBundle
* @param bundle the lineBundle * @param bundle the lineBundle
* @param srcLocations the according source locations * @param cols column coordinates in the line bundle
* @param newLocations matched source locations
* @param colors colors for the markers. Defaults to white. * @param colors colors for the markers. Defaults to white.
*/ */
CV_EXPORTS_W void drawCorrespondencies(InputOutputArray bundle, InputArray srcLocations, CV_EXPORTS_W void drawCorrespondencies(InputOutputArray bundle, InputArray cols,
InputArray newLocations, InputArray colors = noArray()); InputArray colors = noArray());
/** /**
* Debug draw search lines onto an image * Debug draw search lines onto an image
* @param img the output image * @param img the output image
@ -83,20 +83,22 @@ CV_EXPORTS_W void extractLineBundle(int len, InputArray ctl2d, InputArray img, O
* Find corresponding image locations by searching for a maximal sobel edge along the search line (a single * Find corresponding image locations by searching for a maximal sobel edge along the search line (a single
* row in the bundle) * row in the bundle)
* @param bundle the line bundle * @param bundle the line bundle
* @param srcLocations the according source image location * @param cols correspondence-position per line in line-bundle-space
* @param newLocations image locations with maximal edge along the search line
* @param response the sobel response for the selected point * @param response the sobel response for the selected point
*/ */
CV_EXPORTS_W void findCorrespondencies(InputArray bundle, InputArray srcLocations, OutputArray newLocations, CV_EXPORTS_W void findCorrespondencies(InputArray bundle, OutputArray cols,
OutputArray response = noArray()); OutputArray response = noArray());
/** /**
* Filter corresponding 2d and 3d points based on mask * Collect corresponding 2d and 3d points based on correspondencies and mask
* @param cols correspondence-position per line in line-bundle-space
* @param srcLocations the source image location
* @param pts2d 2d points * @param pts2d 2d points
* @param pts3d 3d points * @param pts3d 3d points
* @param mask mask containing non-zero values for the elements to be retained * @param mask mask containing non-zero values for the elements to be retained
*/ */
CV_EXPORTS_W void filterCorrespondencies(InputOutputArray pts2d, InputOutputArray pts3d, InputArray mask); CV_EXPORTS_W void convertCorrespondencies(InputArray cols, InputArray srcLocations, OutputArray pts2d,
InputOutputArray pts3d = noArray(), InputArray mask = noArray());
/** /**
* High level function to execute a single rapid @cite harris1990rapid iteration * High level function to execute a single rapid @cite harris1990rapid iteration
@ -104,7 +106,7 @@ CV_EXPORTS_W void filterCorrespondencies(InputOutputArray pts2d, InputOutputArra
* 1. @ref extractControlPoints * 1. @ref extractControlPoints
* 2. @ref extractLineBundle * 2. @ref extractLineBundle
* 3. @ref findCorrespondencies * 3. @ref findCorrespondencies
* 4. @ref filterCorrespondencies * 4. @ref convertCorrespondencies
* 5. @ref solvePnPRefineLM * 5. @ref solvePnPRefineLM
* *
* @param img the video frame * @param img the video frame
@ -115,10 +117,11 @@ CV_EXPORTS_W void filterCorrespondencies(InputOutputArray pts2d, InputOutputArra
* @param K camera matrix * @param K camera matrix
* @param rvec rotation between mesh and camera. Input values are used as an initial solution. * @param rvec rotation between mesh and camera. Input values are used as an initial solution.
* @param tvec translation between mesh and camera. Input values are used as an initial solution. * @param tvec translation between mesh and camera. Input values are used as an initial solution.
* @param rmsd the 2d reprojection difference
* @return ratio of search lines that could be extracted and matched * @return ratio of search lines that could be extracted and matched
*/ */
CV_EXPORTS_W float rapid(InputArray img, int num, int len, InputArray pts3d, InputArray tris, InputArray K, CV_EXPORTS_W float rapid(InputArray img, int num, int len, InputArray pts3d, InputArray tris, InputArray K,
InputOutputArray rvec, InputOutputArray tvec); InputOutputArray rvec, InputOutputArray tvec, CV_OUT double* rmsd = 0);
//! @} //! @}
} /* namespace rapid */ } /* namespace rapid */
} /* namespace cv */ } /* namespace cv */

@ -35,7 +35,7 @@ while cv.waitKey(1) != 27:
# tracking and refinement with rapid # tracking and refinement with rapid
if rot is not None: if rot is not None:
for i in range(5): # multiple iterations for i in range(5): # multiple iterations
ratio, rot, trans = cv.rapid.rapid(img, 40, line_len, obj_points, tris, K, rot, trans) ratio, rot, trans = cv.rapid.rapid(img, 40, line_len, obj_points, tris, K, rot, trans)[:3]
if ratio < 0.8: if ratio < 0.8:
# bad quality, force re-detect # bad quality, force re-detect
rot, trans = None, None rot, trans = None, None

@ -223,19 +223,13 @@ static void compute1DSobel(const Mat& src, Mat& dst)
} }
} }
void findCorrespondencies(InputArray bundle, InputArray _srcLocations, OutputArray _newLocations, void findCorrespondencies(InputArray bundle, OutputArray _cols, OutputArray _response)
OutputArray _response)
{ {
CV_Assert(bundle.size() == _srcLocations.size());
CV_CheckTypeEQ(_srcLocations.type(), CV_16SC2, "Vec2s data type expected");
Mat_<uchar> sobel; Mat_<uchar> sobel;
compute1DSobel(bundle.getMat(), sobel); compute1DSobel(bundle.getMat(), sobel);
_newLocations.create(sobel.rows, 1, CV_16SC2); _cols.create(sobel.rows, 1, CV_32S);
Mat_<int> cols = _cols.getMat();
Mat newLocations = _newLocations.getMat();
Mat srcLocations = _srcLocations.getMat();
Mat_<uchar> response; Mat_<uchar> response;
if (_response.needed()) { if (_response.needed()) {
@ -267,64 +261,75 @@ void findCorrespondencies(InputArray bundle, InputArray _srcLocations, OutputArr
if (!response.empty()) if (!response.empty())
response(i) = mx; response(i) = mx;
newLocations.at<Vec2s>(i, 0) = srcLocations.at<Vec2s>(i, pos); cols(i) = pos;
} }
} }
void drawCorrespondencies(InputOutputArray _bundle, InputArray _srcLocations, InputArray _newLocations, void drawCorrespondencies(InputOutputArray _bundle, InputArray _cols, InputArray _colors)
InputArray _colors)
{ {
CV_CheckTypeEQ(_srcLocations.type(), CV_16SC2, "Vec2s data type expected"); CV_CheckTypeEQ(_cols.type(), CV_32S, "cols must be of int type");
CV_CheckTypeEQ(_newLocations.type(), CV_16SC2, "Vec2s data type expected"); CV_Assert(_bundle.rows() == _cols.rows());
CV_Assert(_bundle.size() == _srcLocations.size()); CV_Assert(_colors.empty() || _colors.rows() == _cols.rows());
CV_Assert(_colors.empty() || _colors.rows() == _srcLocations.rows());
Mat bundle = _bundle.getMat(); Mat bundle = _bundle.getMat();
Mat_<Vec2s> srcLocations = _srcLocations.getMat(); Mat_<int> cols = _cols.getMat();
Mat_<Vec2s> newLocations = _newLocations.getMat();
Mat_<Vec4d> colors = _colors.getMat(); Mat_<Vec4d> colors = _colors.getMat();
for (int i = 0; i < bundle.rows; i++) { for (int i = 0; i < bundle.rows; i++) {
const Vec2s& ref = newLocations(i); bundle(Rect(Point(cols(i), i), Size(1, 1))) = colors.empty() ? Scalar::all(255) : colors(i);
for (int j = 1; j < bundle.cols - 1; j++) {
if (ref == srcLocations(i, j)) {
bundle(Rect(Point(j, i), Size(1, 1))) = colors.empty() ? Scalar::all(255) : colors(i);
}
}
} }
} }
void filterCorrespondencies(InputOutputArray _pts2d, InputOutputArray _pts3d, InputArray _mask) void convertCorrespondencies(InputArray _cols, InputArray _srcLocations, OutputArray _pts2d,
InputOutputArray _pts3d, InputArray _mask)
{ {
CV_CheckTypeEQ(_mask.type(), CV_8UC1, "mask must be of uchar type"); CV_CheckTypeEQ(_cols.type(), CV_32S, "cols must be of int type");
CV_Assert(_pts2d.rows() == _pts3d.rows() && _pts2d.rows() == _mask.rows()); CV_CheckTypeEQ(_srcLocations.type(), CV_16SC2, "Vec2s data type expected");
CV_Assert(_srcLocations.rows() == _cols.rows());
Mat_<cv::Vec2s> srcLocations = _srcLocations.getMat();
Mat_<int> cols = _cols.getMat();
Mat pts2d = _pts2d.getMat(); Mat pts2d = Mat(0, 1, CV_16SC2);
Mat pts3d = _pts3d.getMat(); pts2d.reserve(cols.rows);
Mat_<uchar> mask = _mask.getMat();
Mat opts3d(0, 1, pts3d.type()); Mat_<uchar> mask;
opts3d.reserve(mask.rows); if (!_mask.empty())
Mat opts2d(0, 1, pts2d.type()); {
opts2d.reserve(mask.rows); CV_CheckTypeEQ(_mask.type(), CV_8UC1, "mask must be of uchar type");
CV_Assert(_cols.rows() == _mask.rows());
mask = _mask.getMat();
}
Mat pts3d;
Mat opts3d;
if(!_pts3d.empty())
{
CV_Assert(_cols.rows() == _pts3d.rows());
pts3d = _pts3d.getMat();
opts3d.create(0, 1, pts3d.type());
opts3d.reserve(cols.rows);
}
for (int i = 0; i < mask.rows; i++) { for (int i = 0; i < cols.rows; i++) {
if (!mask(i)) if (!mask.empty() && !mask(i))
continue; continue;
opts2d.push_back(pts2d.row(i)); pts2d.push_back(srcLocations(i, cols(i)));
opts3d.push_back(pts3d.row(i)); if(!pts3d.empty())
opts3d.push_back(pts3d.row(i));
} }
Mat(opts3d).copyTo(_pts3d); pts2d.copyTo(_pts2d);
Mat(opts2d).copyTo(_pts2d); if(!pts3d.empty())
opts3d.copyTo(_pts3d);
} }
float rapid(InputArray img, int num, int len, InputArray vtx, InputArray tris, InputArray K, float rapid(InputArray img, int num, int len, InputArray vtx, InputArray tris, InputArray K,
InputOutputArray rvec, InputOutputArray tvec) InputOutputArray rvec, InputOutputArray tvec, double* rmsd)
{ {
CV_Assert(num >= 3); CV_Assert(num >= 3);
Mat pts2d, pts3d, correspondencies; Mat pts2d, pts3d;
extractControlPoints(num, len, vtx, rvec, tvec, K, img.size(), tris, pts2d, pts3d); extractControlPoints(num, len, vtx, rvec, tvec, K, img.size(), tris, pts2d, pts3d);
if (pts2d.empty()) if (pts2d.empty())
return 0; return 0;
@ -332,18 +337,26 @@ float rapid(InputArray img, int num, int len, InputArray vtx, InputArray tris, I
Mat lineBundle, imgLoc; Mat lineBundle, imgLoc;
extractLineBundle(len, pts2d, img, lineBundle, imgLoc); extractLineBundle(len, pts2d, img, lineBundle, imgLoc);
Mat response; Mat cols, response;
findCorrespondencies(lineBundle, imgLoc, correspondencies, response); findCorrespondencies(lineBundle, cols, response);
const uchar sobel_thresh = 20; const uchar sobel_thresh = 20;
filterCorrespondencies(correspondencies, pts3d, response > sobel_thresh); Mat mask = response > sobel_thresh;
convertCorrespondencies(cols, imgLoc, pts2d, pts3d, mask);
if(rmsd)
{
cols.copyTo(cols, mask);
cols -= len + 1;
*rmsd = std::sqrt(norm(cols, NORM_L2SQR) / cols.rows);
}
if (correspondencies.rows < 3) if (pts2d.rows < 3)
return 0; return 0;
solvePnPRefineLM(pts3d, correspondencies, K, cv::noArray(), rvec, tvec); solvePnPRefineLM(pts3d, pts2d, K, cv::noArray(), rvec, tvec);
return float(correspondencies.rows) / num; return float(pts2d.rows) / num;
} }
} /* namespace rapid */ } /* namespace rapid */

Loading…
Cancel
Save