mirror of
https://github.com/opencv/opencv.git
synced 2026-07-30 07:43:03 +04:00
Merge pull request #29175 from asmorkalov:as/geometry2
Geometry module #29175 OpenCV Contrib: https://github.com/opencv/opencv_contrib/pull/4129 CI changes: https://github.com/opencv/ci-gha-workflow/pull/313 Continues - https://github.com/opencv/opencv/pull/28804 - https://github.com/opencv/opencv/pull/29101 - https://github.com/opencv/opencv/pull/29108 - https://github.com/opencv/opencv/pull/28810 Todo for followup PRs: - [x] Rename doxygen groups - [x] Fix JS modules layout and whitelists - [ ] Sort tutorials code/snippets ### Pull Request Readiness Checklist See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request - [x] I agree to contribute to the project under Apache 2 License. - [x] To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV - [x] The PR is proposed to the proper branch - [ ] There is a reference to the original bug report and related work - [ ] There is accuracy test, performance test and test data in opencv_extra repository, if applicable Patch to opencv_extra has the same branch name. - [ ] The feature is well documented and sample code can be built with the project CMake
This commit is contained in:
committed by
GitHub
parent
14a475aa0b
commit
59218f9edd
@@ -0,0 +1,20 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html
|
||||
|
||||
#ifndef OPENCV_GEOMETRY_HPP
|
||||
#define OPENCV_GEOMETRY_HPP
|
||||
|
||||
/**
|
||||
@defgroup geometry Computational geometry primitives module.
|
||||
*/
|
||||
|
||||
//! @addtogroup geometry
|
||||
//! @{
|
||||
|
||||
#include "opencv2/geometry/2d.hpp"
|
||||
#include "opencv2/geometry/3d.hpp"
|
||||
|
||||
//! @} geometry
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,811 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html
|
||||
|
||||
#ifndef OPENCV_2D_HPP
|
||||
#define OPENCV_2D_HPP
|
||||
|
||||
#include "opencv2/core.hpp"
|
||||
#include "opencv2/core/utils/logger.hpp"
|
||||
|
||||
namespace cv {
|
||||
|
||||
//! @addtogroup geometry_shape
|
||||
//! @{
|
||||
|
||||
//! types of intersection between rectangles
|
||||
enum RectanglesIntersectTypes {
|
||||
INTERSECT_NONE = 0, //!< No intersection
|
||||
INTERSECT_PARTIAL = 1, //!< There is a partial intersection
|
||||
INTERSECT_FULL = 2 //!< One of the rectangle is fully enclosed in the other
|
||||
};
|
||||
|
||||
//! Variants of Line Segment %Detector
|
||||
enum LineSegmentDetectorModes {
|
||||
LSD_REFINE_NONE = 0, //!< No refinement applied
|
||||
LSD_REFINE_STD = 1, //!< Standard refinement is applied. E.g. breaking arches into smaller straighter line approximations.
|
||||
LSD_REFINE_ADV = 2 //!< Advanced refinement. Number of false alarms is calculated, lines are
|
||||
//!< refined through increase of precision, decrement in size, etc.
|
||||
};
|
||||
|
||||
//! @addtogroup geometry_subdiv2d
|
||||
//! @{
|
||||
|
||||
class CV_EXPORTS_W Subdiv2D
|
||||
{
|
||||
public:
|
||||
/** Subdiv2D point location cases */
|
||||
enum { PTLOC_ERROR = -2, //!< Point location error
|
||||
PTLOC_OUTSIDE_RECT = -1, //!< Point outside the subdivision bounding rect
|
||||
PTLOC_INSIDE = 0, //!< Point inside some facet
|
||||
PTLOC_VERTEX = 1, //!< Point coincides with one of the subdivision vertices
|
||||
PTLOC_ON_EDGE = 2 //!< Point on some edge
|
||||
};
|
||||
|
||||
/** Subdiv2D edge type navigation (see: getEdge()) */
|
||||
enum { NEXT_AROUND_ORG = 0x00,
|
||||
NEXT_AROUND_DST = 0x22,
|
||||
PREV_AROUND_ORG = 0x11,
|
||||
PREV_AROUND_DST = 0x33,
|
||||
NEXT_AROUND_LEFT = 0x13,
|
||||
NEXT_AROUND_RIGHT = 0x31,
|
||||
PREV_AROUND_LEFT = 0x20,
|
||||
PREV_AROUND_RIGHT = 0x02
|
||||
};
|
||||
|
||||
/** creates an empty Subdiv2D object.
|
||||
* To create a new empty Delaunay subdivision you need to use the #initDelaunay function.
|
||||
*/
|
||||
CV_WRAP Subdiv2D();
|
||||
|
||||
/** @overload
|
||||
*
|
||||
* @param rect Rectangle that includes all of the 2D points that are to be added to the subdivision.
|
||||
*
|
||||
* The function creates an empty Delaunay subdivision where 2D points can be added using the function
|
||||
* insert() . All of the points to be added must be within the specified rectangle, otherwise a runtime
|
||||
* error is raised.
|
||||
*/
|
||||
CV_WRAP Subdiv2D(Rect rect);
|
||||
|
||||
/** @overload */
|
||||
CV_WRAP Subdiv2D(Rect2f rect2f);
|
||||
|
||||
/** @overload
|
||||
*
|
||||
* @brief Creates a new empty Delaunay subdivision
|
||||
*
|
||||
* @param rect Rectangle that includes all of the 2D points that are to be added to the subdivision.
|
||||
*
|
||||
*/
|
||||
CV_WRAP void initDelaunay(Rect rect);
|
||||
|
||||
/** @overload
|
||||
*
|
||||
* @brief Creates a new empty Delaunay subdivision
|
||||
*
|
||||
* @param rect Rectangle that includes all of the 2d points that are to be added to the subdivision.
|
||||
*
|
||||
*/
|
||||
CV_WRAP_AS(initDelaunay2f) CV_WRAP void initDelaunay(Rect2f rect);
|
||||
|
||||
/** @brief Insert a single point into a Delaunay triangulation.
|
||||
*
|
||||
* @param pt Point to insert.
|
||||
*
|
||||
* The function inserts a single point into a subdivision and modifies the subdivision topology
|
||||
* appropriately. If a point with the same coordinates exists already, no new point is added.
|
||||
* @returns the ID of the point.
|
||||
*
|
||||
* @note If the point is outside of the triangulation specified rect a runtime error is raised.
|
||||
*/
|
||||
CV_WRAP int insert(Point2f pt);
|
||||
|
||||
/** @brief Insert multiple points into a Delaunay triangulation.
|
||||
*
|
||||
* @param ptvec Points to insert.
|
||||
*
|
||||
* The function inserts a vector of points into a subdivision and modifies the subdivision topology
|
||||
* appropriately.
|
||||
*/
|
||||
CV_WRAP void insert(const std::vector<Point2f>& ptvec);
|
||||
|
||||
/** @brief Returns the location of a point within a Delaunay triangulation.
|
||||
*
|
||||
* @param pt Point to locate.
|
||||
* @param edge Output edge that the point belongs to or is located to the right of it.
|
||||
* @param vertex Optional output vertex the input point coincides with.
|
||||
*
|
||||
* The function locates the input point within the subdivision and gives one of the triangle edges
|
||||
* or vertices.
|
||||
*
|
||||
* @returns an integer which specify one of the following five cases for point location:
|
||||
* - The point falls into some facet. The function returns #PTLOC_INSIDE and edge will contain one of
|
||||
* edges of the facet.
|
||||
* - The point falls onto the edge. The function returns #PTLOC_ON_EDGE and edge will contain this edge.
|
||||
* - The point coincides with one of the subdivision vertices. The function returns #PTLOC_VERTEX and
|
||||
* vertex will contain a pointer to the vertex.
|
||||
* - The point is outside the subdivision reference rectangle. The function returns #PTLOC_OUTSIDE_RECT
|
||||
* and no pointers are filled.
|
||||
* - One of input arguments is invalid. A runtime error is raised or, if silent or "parent" error
|
||||
* processing mode is selected, #PTLOC_ERROR is returned.
|
||||
*/
|
||||
CV_WRAP int locate(Point2f pt, CV_OUT int& edge, CV_OUT int& vertex);
|
||||
|
||||
/** @brief Finds the subdivision vertex closest to the given point.
|
||||
*
|
||||
* @param pt Input point.
|
||||
* @param nearestPt Output subdivision vertex point.
|
||||
*
|
||||
* The function is another function that locates the input point within the subdivision. It finds the
|
||||
* subdivision vertex that is the closest to the input point. It is not necessarily one of vertices
|
||||
* of the facet containing the input point, though the facet (located using locate() ) is used as a
|
||||
* starting point.
|
||||
*
|
||||
* @returns vertex ID.
|
||||
*/
|
||||
CV_WRAP int findNearest(Point2f pt, CV_OUT Point2f* nearestPt = 0);
|
||||
|
||||
/** @brief Returns a list of all edges.
|
||||
*
|
||||
* @param edgeList Output vector.
|
||||
*
|
||||
* The function gives each edge as a 4 numbers vector, where each two are one of the edge
|
||||
* vertices. i.e. org_x = v[0], org_y = v[1], dst_x = v[2], dst_y = v[3].
|
||||
*/
|
||||
CV_WRAP void getEdgeList(CV_OUT std::vector<Vec4f>& edgeList) const;
|
||||
|
||||
/** @brief Returns a list of the leading edge ID connected to each triangle.
|
||||
*
|
||||
* @param leadingEdgeList Output vector.
|
||||
*
|
||||
* The function gives one edge ID for each triangle.
|
||||
*/
|
||||
CV_WRAP void getLeadingEdgeList(CV_OUT std::vector<int>& leadingEdgeList) const;
|
||||
|
||||
/** @brief Returns a list of all triangles.
|
||||
*
|
||||
* @param triangleList Output vector.
|
||||
*
|
||||
* The function gives each triangle as a 6 numbers vector, where each two are one of the triangle
|
||||
* vertices. i.e. p1_x = v[0], p1_y = v[1], p2_x = v[2], p2_y = v[3], p3_x = v[4], p3_y = v[5].
|
||||
*/
|
||||
CV_WRAP void getTriangleList(CV_OUT std::vector<Vec6f>& triangleList) const;
|
||||
|
||||
/** @brief Returns a list of all Voronoi facets.
|
||||
*
|
||||
* @param idx Vector of vertices IDs to consider. For all vertices you can pass empty vector.
|
||||
* @param facetList Output vector of the Voronoi facets.
|
||||
* @param facetCenters Output vector of the Voronoi facets center points.
|
||||
*
|
||||
*/
|
||||
CV_WRAP void getVoronoiFacetList(const std::vector<int>& idx, CV_OUT std::vector<std::vector<Point2f> >& facetList,
|
||||
CV_OUT std::vector<Point2f>& facetCenters);
|
||||
|
||||
/** @brief Returns vertex location from vertex ID.
|
||||
*
|
||||
* @param vertex vertex ID.
|
||||
* @param firstEdge Optional. The first edge ID which is connected to the vertex.
|
||||
* @returns vertex (x,y)
|
||||
*
|
||||
*/
|
||||
CV_WRAP Point2f getVertex(int vertex, CV_OUT int* firstEdge = 0) const;
|
||||
|
||||
/** @brief Returns one of the edges related to the given edge.
|
||||
*
|
||||
* @param edge Subdivision edge ID.
|
||||
* @param nextEdgeType Parameter specifying which of the related edges to return.
|
||||
* The following values are possible:
|
||||
* - NEXT_AROUND_ORG next around the edge origin ( eOnext on the picture below if e is the input edge)
|
||||
* - NEXT_AROUND_DST next around the edge vertex ( eDnext )
|
||||
* - PREV_AROUND_ORG previous around the edge origin (reversed eRnext )
|
||||
* - PREV_AROUND_DST previous around the edge destination (reversed eLnext )
|
||||
* - NEXT_AROUND_LEFT next around the left facet ( eLnext )
|
||||
* - NEXT_AROUND_RIGHT next around the right facet ( eRnext )
|
||||
* - PREV_AROUND_LEFT previous around the left facet (reversed eOnext )
|
||||
* - PREV_AROUND_RIGHT previous around the right facet (reversed eDnext )
|
||||
*
|
||||
* 
|
||||
*
|
||||
* @returns edge ID related to the input edge.
|
||||
*/
|
||||
CV_WRAP int getEdge( int edge, int nextEdgeType ) const;
|
||||
|
||||
/** @brief Returns next edge around the edge origin.
|
||||
*
|
||||
* @param edge Subdivision edge ID.
|
||||
*
|
||||
* @returns an integer which is next edge ID around the edge origin: eOnext on the
|
||||
* picture above if e is the input edge).
|
||||
*/
|
||||
CV_WRAP int nextEdge(int edge) const;
|
||||
|
||||
/** @brief Returns another edge of the same quad-edge.
|
||||
*
|
||||
* @param edge Subdivision edge ID.
|
||||
* @param rotate Parameter specifying which of the edges of the same quad-edge as the input
|
||||
* one to return. The following values are possible:
|
||||
* - 0 - the input edge ( e on the picture below if e is the input edge)
|
||||
* - 1 - the rotated edge ( eRot )
|
||||
* - 2 - the reversed edge (reversed e (in green))
|
||||
* - 3 - the reversed rotated edge (reversed eRot (in green))
|
||||
*
|
||||
* @returns one of the edges ID of the same quad-edge as the input edge.
|
||||
*/
|
||||
CV_WRAP int rotateEdge(int edge, int rotate) const;
|
||||
CV_WRAP int symEdge(int edge) const;
|
||||
|
||||
/** @brief Returns the edge origin.
|
||||
*
|
||||
* @param edge Subdivision edge ID.
|
||||
* @param orgpt Output vertex location.
|
||||
*
|
||||
* @returns vertex ID.
|
||||
*/
|
||||
CV_WRAP int edgeOrg(int edge, CV_OUT Point2f* orgpt = 0) const;
|
||||
|
||||
/** @brief Returns the edge destination.
|
||||
*
|
||||
* @param edge Subdivision edge ID.
|
||||
* @param dstpt Output vertex location.
|
||||
*
|
||||
* @returns vertex ID.
|
||||
*/
|
||||
CV_WRAP int edgeDst(int edge, CV_OUT Point2f* dstpt = 0) const;
|
||||
|
||||
protected:
|
||||
int newEdge();
|
||||
void deleteEdge(int edge);
|
||||
int newPoint(Point2f pt, bool isvirtual, int firstEdge = 0);
|
||||
void deletePoint(int vtx);
|
||||
void setEdgePoints( int edge, int orgPt, int dstPt );
|
||||
void splice( int edgeA, int edgeB );
|
||||
int connectEdges( int edgeA, int edgeB );
|
||||
void swapEdges( int edge );
|
||||
int isRightOf(Point2f pt, int edge) const;
|
||||
void calcVoronoi();
|
||||
void clearVoronoi();
|
||||
void checkSubdiv() const;
|
||||
|
||||
struct CV_EXPORTS Vertex
|
||||
{
|
||||
Vertex();
|
||||
Vertex(Point2f pt, bool isvirtual, int firstEdge=0);
|
||||
bool isvirtual() const;
|
||||
bool isfree() const;
|
||||
|
||||
int firstEdge;
|
||||
int type;
|
||||
Point2f pt;
|
||||
};
|
||||
|
||||
struct CV_EXPORTS QuadEdge
|
||||
{
|
||||
QuadEdge();
|
||||
QuadEdge(int edgeidx);
|
||||
bool isfree() const;
|
||||
|
||||
int next[4];
|
||||
int pt[4];
|
||||
};
|
||||
|
||||
//! All of the vertices
|
||||
std::vector<Vertex> vtx;
|
||||
//! All of the edges
|
||||
std::vector<QuadEdge> qedges;
|
||||
int freeQEdge;
|
||||
int freePoint;
|
||||
bool validGeometry;
|
||||
|
||||
int recentEdge;
|
||||
//! Top left corner of the bounding rect
|
||||
Point2f topLeft;
|
||||
//! Bottom right corner of the bounding rect
|
||||
Point2f bottomRight;
|
||||
};
|
||||
|
||||
//! @} geometry_subdiv2d
|
||||
|
||||
//! @addtogroup geometry_feature
|
||||
//! @{
|
||||
|
||||
/** @example samples/cpp/snippets/lsd_lines.cpp
|
||||
An example using the LineSegmentDetector
|
||||
\image html building_lsd.png "Sample output image" width=434 height=300
|
||||
*/
|
||||
|
||||
/** @brief Line segment detector class
|
||||
|
||||
following the algorithm described at @cite Rafael12 .
|
||||
|
||||
@note Implementation has been removed from OpenCV version 3.4.6 to 3.4.15 and version 4.1.0 to 4.5.3 due original code license conflict.
|
||||
restored again after [Computation of a NFA](https://github.com/rafael-grompone-von-gioi/binomial_nfa) code published under the MIT license.
|
||||
*/
|
||||
class CV_EXPORTS_W LineSegmentDetector : public Algorithm
|
||||
{
|
||||
public:
|
||||
|
||||
/** @brief Finds lines in the input image.
|
||||
|
||||
This is the output of the default parameters of the algorithm on the above shown image.
|
||||
|
||||

|
||||
|
||||
@param image A grayscale (CV_8UC1) input image. If only a roi needs to be selected, use:
|
||||
`lsd_ptr-\>detect(image(roi), lines, ...); lines += Scalar(roi.x, roi.y, roi.x, roi.y);`
|
||||
@param lines A vector of Vec4f elements specifying the beginning and ending point of a line. Where
|
||||
Vec4f is (x1, y1, x2, y2), point 1 is the start, point 2 - end. Returned lines are strictly
|
||||
oriented depending on the gradient.
|
||||
@param width Vector of widths of the regions, where the lines are found. E.g. Width of line.
|
||||
@param prec Vector of precisions with which the lines are found.
|
||||
@param nfa Vector containing number of false alarms in the line region, with precision of 10%. The
|
||||
bigger the value, logarithmically better the detection.
|
||||
- -1 corresponds to 10 mean false alarms
|
||||
- 0 corresponds to 1 mean false alarm
|
||||
- 1 corresponds to 0.1 mean false alarms
|
||||
This vector will be calculated only when the objects type is #LSD_REFINE_ADV.
|
||||
*/
|
||||
CV_WRAP virtual void detect(InputArray image, OutputArray lines,
|
||||
OutputArray width = noArray(), OutputArray prec = noArray(),
|
||||
OutputArray nfa = noArray()) = 0;
|
||||
|
||||
/** @brief Draws the line segments on a given image.
|
||||
@param image The image, where the lines will be drawn. Should be bigger or equal to the image,
|
||||
where the lines were found.
|
||||
@param lines A vector of the lines that needed to be drawn.
|
||||
*/
|
||||
CV_WRAP virtual void drawSegments(InputOutputArray image, InputArray lines) = 0;
|
||||
|
||||
/** @brief Draws two groups of lines in blue and red, counting the non overlapping (mismatching) pixels.
|
||||
|
||||
@param size The size of the image, where lines1 and lines2 were found.
|
||||
@param lines1 The first group of lines that needs to be drawn. It is visualized in blue color.
|
||||
@param lines2 The second group of lines. They visualized in red color.
|
||||
@param image Optional image, where the lines will be drawn. The image should be color(3-channel)
|
||||
in order for lines1 and lines2 to be drawn in the above mentioned colors.
|
||||
*/
|
||||
CV_WRAP virtual int compareSegments(const Size& size, InputArray lines1, InputArray lines2, InputOutputArray image = noArray()) = 0;
|
||||
|
||||
virtual ~LineSegmentDetector() { }
|
||||
};
|
||||
|
||||
/** @brief Creates a smart pointer to a LineSegmentDetector object and initializes it.
|
||||
|
||||
The LineSegmentDetector algorithm is defined using the standard values. Only advanced users may want
|
||||
to edit those, as to tailor it for their own application.
|
||||
|
||||
@param refine The way found lines will be refined, see #LineSegmentDetectorModes
|
||||
@param scale The scale of the image that will be used to find the lines. Range (0..1].
|
||||
@param sigma_scale Sigma for Gaussian filter. It is computed as sigma = sigma_scale/scale.
|
||||
@param quant Bound to the quantization error on the gradient norm.
|
||||
@param ang_th Gradient angle tolerance in degrees.
|
||||
@param log_eps Detection threshold: -log10(NFA) \> log_eps. Used only when advance refinement is chosen.
|
||||
@param density_th Minimal density of aligned region points in the enclosing rectangle.
|
||||
@param n_bins Number of bins in pseudo-ordering of gradient modulus.
|
||||
*/
|
||||
CV_EXPORTS_W Ptr<LineSegmentDetector> createLineSegmentDetector(
|
||||
LineSegmentDetectorModes refine = LSD_REFINE_STD, double scale = 0.8,
|
||||
double sigma_scale = 0.6, double quant = 2.0, double ang_th = 22.5,
|
||||
double log_eps = 0, double density_th = 0.7, int n_bins = 1024);
|
||||
|
||||
//! @} geometry_feature
|
||||
|
||||
/** @example samples/python/snippets/squares.py
|
||||
A n example using approxPolyDP function in python. *
|
||||
*/
|
||||
|
||||
/** @brief Approximates a polygonal curve(s) with the specified precision.
|
||||
*
|
||||
T he function cv::approxPolyDP approximates a curve or a p*olygon with another curve/polygon with less
|
||||
vertices so that the distance between them is less or equal to the specified precision. It uses the
|
||||
Douglas-Peucker algorithm <https://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm>
|
||||
|
||||
@param curve Input vector of a 2D point stored in std::vector or Mat
|
||||
@param approxCurve Result of the approximation. The type should match the type of the input curve.
|
||||
@param epsilon Parameter specifying the approximation accuracy. This is the maximum distance
|
||||
between the original curve and its approximation.
|
||||
@param closed If true, the approximated curve is closed (its first and last vertices are
|
||||
connected). Otherwise, it is not closed.
|
||||
*/
|
||||
CV_EXPORTS_W void approxPolyDP( InputArray curve,
|
||||
OutputArray approxCurve,
|
||||
double epsilon, bool closed );
|
||||
|
||||
/** @brief Approximates a polygon with a convex hull with a specified accuracy and number of sides.
|
||||
*
|
||||
T he cv::approxPolyN function approximates a polygon with *a convex hull
|
||||
so that the difference between the contour area of the original contour and the new polygon is minimal.
|
||||
It uses a greedy algorithm for contracting two vertices into one in such a way that the additional area is minimal.
|
||||
Straight lines formed by each edge of the convex contour are drawn and the areas of the resulting triangles are considered.
|
||||
Each vertex will lie either on the original contour or outside it.
|
||||
|
||||
The algorithm based on the paper @cite LowIlie2003 .
|
||||
|
||||
@param curve Input vector of a 2D points stored in std::vector or Mat, points must be float or integer.
|
||||
@param approxCurve Result of the approximation. The type is vector of a 2D point (Point2f or Point) in std::vector or Mat.
|
||||
@param nsides The parameter defines the number of sides of the result polygon.
|
||||
@param epsilon_percentage defines the percentage of the maximum of additional area.
|
||||
If it equals -1, it is not used. Otherwise algorithm stops if additional area is greater than contourArea(_curve) * percentage.
|
||||
If additional area exceeds the limit, algorithm returns as many vertices as there were at the moment the limit was exceeded.
|
||||
@param ensure_convex If it is true, algorithm creates a convex hull of input contour. Otherwise input vector should be convex.
|
||||
*/
|
||||
CV_EXPORTS_W void approxPolyN(InputArray curve, OutputArray approxCurve,
|
||||
int nsides, float epsilon_percentage = -1.0,
|
||||
bool ensure_convex = true);
|
||||
|
||||
/** @brief Finds a rotated rectangle of the minimum area enclosing the input 2D point set.
|
||||
*
|
||||
* The function calculates and returns the minimum-area bounding rectangle (possibly rotated) for a
|
||||
* specified point set. The angle of rotation represents the angle between the line connecting the starting
|
||||
* and ending points (based on the clockwise order with greatest index for the corner with greatest \f$y\f$)
|
||||
* and the horizontal axis. This angle always falls between \f$[-90, 0)\f$ because, if the object
|
||||
* rotates more than a rect angle, the next edge is used to measure the angle. The starting and ending points change
|
||||
* as the object rotates.Developer should keep in mind that the returned RotatedRect can contain negative
|
||||
* indices when data is close to the containing Mat element boundary.
|
||||
*
|
||||
* @param points Input vector of 2D points, stored in std::vector\<\> or Mat
|
||||
*/
|
||||
CV_EXPORTS_W RotatedRect minAreaRect( InputArray points );
|
||||
|
||||
/** @brief Finds the four vertices of a rotated rect. Useful to draw the rotated rectangle.
|
||||
*
|
||||
* The function finds the four vertices of a rotated rectangle. The four vertices are returned
|
||||
* in clockwise order starting from the point with greatest \f$y\f$. If two points have the
|
||||
* same \f$y\f$ coordinate the rightmost is the starting point. This function is useful to draw the
|
||||
* rectangle. In C++, instead of using this function, you can directly use RotatedRect::points method. Please
|
||||
* visit the @ref tutorial_bounding_rotated_ellipses "tutorial on Creating Bounding rotated boxes and ellipses
|
||||
* for contours" for more information.
|
||||
*
|
||||
* @param box The input rotated rectangle. It may be the output of @ref minAreaRect.
|
||||
* @param points The output array of four vertices of rectangles.
|
||||
*/
|
||||
CV_EXPORTS_W void boxPoints(RotatedRect box, OutputArray points);
|
||||
|
||||
/** @brief Finds a circle of the minimum area enclosing a 2D point set.
|
||||
*
|
||||
* The function finds the minimal enclosing circle of a 2D point set using an iterative algorithm.
|
||||
*
|
||||
* @param points Input vector of 2D points, stored in std::vector\<\> or Mat
|
||||
* @param center Output center of the circle.
|
||||
* @param radius Output radius of the circle.
|
||||
*/
|
||||
CV_EXPORTS_W void minEnclosingCircle( InputArray points,
|
||||
CV_OUT Point2f& center, CV_OUT float& radius );
|
||||
|
||||
|
||||
/** @brief Finds a triangle of minimum area enclosing a 2D point set and returns its area.
|
||||
*
|
||||
* The function finds a triangle of minimum area enclosing the given set of 2D points and returns its
|
||||
* area. The output for a given 2D point set is shown in the image below. 2D points are depicted in
|
||||
*red* and the enclosing triangle in *yellow*.
|
||||
*
|
||||
* 
|
||||
*
|
||||
* The implementation of the algorithm is based on O'Rourke's @cite ORourke86 and Klee and Laskowski's
|
||||
* @cite KleeLaskowski85 papers. O'Rourke provides a \f$\theta(n)\f$ algorithm for finding the minimal
|
||||
* enclosing triangle of a 2D convex polygon with n vertices. Since the #minEnclosingTriangle function
|
||||
* takes a 2D point set as input an additional preprocessing step of computing the convex hull of the
|
||||
* 2D point set is required. The complexity of the #convexHull function is \f$O(n log(n))\f$ which is higher
|
||||
* than \f$\theta(n)\f$. Thus the overall complexity of the function is \f$O(n log(n))\f$.
|
||||
*
|
||||
* @param points Input vector of 2D points with depth CV_32S or CV_32F, stored in std::vector\<\> or Mat
|
||||
* @param triangle Output vector of three 2D points defining the vertices of the triangle. The depth
|
||||
* of the OutputArray must be CV_32F.
|
||||
*/
|
||||
CV_EXPORTS_W double minEnclosingTriangle( InputArray points, CV_OUT OutputArray triangle );
|
||||
|
||||
|
||||
/**
|
||||
* @brief Finds a convex polygon of minimum area enclosing a 2D point set and returns its area.
|
||||
*
|
||||
* This function takes a given set of 2D points and finds the enclosing polygon with k vertices and minimal
|
||||
* area. It takes the set of points and the parameter k as input and returns the area of the minimal
|
||||
* enclosing polygon.
|
||||
*
|
||||
* The Implementation is based on a paper by Aggarwal, Chang and Yap @cite Aggarwal1985. They
|
||||
* provide a \f$\theta(n²log(n)log(k))\f$ algorithm for finding the minimal convex polygon with k
|
||||
* vertices enclosing a 2D convex polygon with n vertices (k < n). Since the #minEnclosingConvexPolygon
|
||||
* function takes a 2D point set as input, an additional preprocessing step of computing the convex hull
|
||||
* of the 2D point set is required. The complexity of the #convexHull function is \f$O(n log(n))\f$ which
|
||||
* is lower than \f$\theta(n²log(n)log(k))\f$. Thus the overall complexity of the function is
|
||||
* \f$O(n²log(n)log(k))\f$.
|
||||
*
|
||||
* @param points Input vector of 2D points, stored in std::vector\<\> or Mat
|
||||
* @param polygon Output vector of 2D points defining the vertices of the enclosing polygon
|
||||
* @param k Number of vertices of the output polygon
|
||||
*/
|
||||
|
||||
CV_EXPORTS_W double minEnclosingConvexPolygon ( InputArray points, OutputArray polygon, int k );
|
||||
|
||||
|
||||
/** @brief Compares two shapes.
|
||||
*
|
||||
* The function compares two shapes. All three implemented methods use the Hu invariants (see #HuMoments)
|
||||
*
|
||||
* @param contour1 First contour or grayscale image.
|
||||
* @param contour2 Second contour or grayscale image.
|
||||
* @param method Comparison method, see #ShapeMatchModes
|
||||
* @param parameter Method-specific parameter (not supported now).
|
||||
*/
|
||||
CV_EXPORTS_W double matchShapes( InputArray contour1, InputArray contour2,
|
||||
int method, double parameter );
|
||||
|
||||
/** @example samples/cpp/geometry.cpp
|
||||
* An example program illustrates the use of cv::convexHull, cv::fitEllipse, cv::minEnclosingTriangle, cv::minEnclosingCircle and cv::minAreaRect.
|
||||
*/
|
||||
|
||||
/** @brief Finds the convex hull of a point set.
|
||||
*
|
||||
* The function cv::convexHull finds the convex hull of a 2D point set using the Sklansky's algorithm @cite Sklansky82
|
||||
* that has *O(N logN)* complexity in the current implementation.
|
||||
*
|
||||
* @param points Input 2D point set, stored in std::vector or Mat.
|
||||
* @param hull Output convex hull. It is either an integer vector of indices or vector of points. In
|
||||
* the first case, the hull elements are 0-based indices of the convex hull points in the original
|
||||
* array (since the set of convex hull points is a subset of the original point set). In the second
|
||||
* case, hull elements are the convex hull points themselves.
|
||||
* @param clockwise Orientation flag. If it is true, the output convex hull is oriented clockwise.
|
||||
* Otherwise, it is oriented counter-clockwise. The assumed coordinate system has its X axis pointing
|
||||
* to the right, and its Y axis pointing upwards.
|
||||
* @param returnPoints Operation flag. In case of a matrix, when the flag is true, the function
|
||||
* returns convex hull points. Otherwise, it returns indices of the convex hull points. When the
|
||||
* output array is std::vector, the flag is ignored, and the output depends on the type of the
|
||||
* vector: std::vector\<int\> implies returnPoints=false, std::vector\<Point\> implies
|
||||
* returnPoints=true.
|
||||
*
|
||||
* @note `points` and `hull` should be different arrays, inplace processing isn't supported.
|
||||
*
|
||||
* Check @ref tutorial_hull "the corresponding tutorial" for more details.
|
||||
*
|
||||
* useful links:
|
||||
*
|
||||
* https://www.learnopencv.com/convex-hull-using-opencv-in-python-and-c/
|
||||
*/
|
||||
CV_EXPORTS_W void convexHull( InputArray points, OutputArray hull,
|
||||
bool clockwise = false, bool returnPoints = true );
|
||||
|
||||
/** @brief Finds the convexity defects of a contour.
|
||||
*
|
||||
* The figure below displays convexity defects of a hand contour:
|
||||
*
|
||||
* 
|
||||
*
|
||||
* @param contour Input contour.
|
||||
* @param convexhull Convex hull obtained using convexHull that should contain indices of the contour
|
||||
* points that make the hull.
|
||||
* @param convexityDefects The output vector of convexity defects. In C++ and the new Python/Java
|
||||
* interface each convexity defect is represented as 4-element integer vector (a.k.a. #Vec4i):
|
||||
* (start_index, end_index, farthest_pt_index, fixpt_depth), where indices are 0-based indices
|
||||
* in the original contour of the convexity defect beginning, end and the farthest point, and
|
||||
* fixpt_depth is fixed-point approximation (with 8 fractional bits) of the distance between the
|
||||
* farthest contour point and the hull. That is, to get the floating-point value of the depth will be
|
||||
* fixpt_depth/256.0.
|
||||
*/
|
||||
CV_EXPORTS_W void convexityDefects( InputArray contour, InputArray convexhull, OutputArray convexityDefects );
|
||||
|
||||
/** @brief Tests a contour convexity.
|
||||
*
|
||||
* The function tests whether the input contour is convex or not. The contour must be simple, that is,
|
||||
* without self-intersections. Otherwise, the function output is undefined.
|
||||
*
|
||||
* @param contour Input vector of 2D points, stored in std::vector\<\> or Mat
|
||||
*/
|
||||
CV_EXPORTS_W bool isContourConvex( InputArray contour );
|
||||
|
||||
/** @example samples/cpp/snippets/intersectExample.cpp
|
||||
* Examples of how intersectConvexConvex works
|
||||
*/
|
||||
|
||||
/** @brief Finds intersection of two convex polygons
|
||||
*
|
||||
* @param p1 First polygon
|
||||
* @param p2 Second polygon
|
||||
* @param p12 Output polygon describing the intersecting area
|
||||
* @param handleNested When true, an intersection is found if one of the polygons is fully enclosed in the other.
|
||||
* When false, no intersection is found. If the polygons share a side or the vertex of one polygon lies on an edge
|
||||
* of the other, they are not considered nested and an intersection will be found regardless of the value of handleNested.
|
||||
*
|
||||
* @returns Area of intersecting polygon. May be negative, if algorithm has not converged, e.g. non-convex input.
|
||||
*
|
||||
* @note intersectConvexConvex doesn't confirm that both polygons are convex and will return invalid results if they aren't.
|
||||
*/
|
||||
CV_EXPORTS_W float intersectConvexConvex( InputArray p1, InputArray p2,
|
||||
OutputArray p12, bool handleNested = true );
|
||||
|
||||
|
||||
/** @brief Fits an ellipse around a set of 2D points.
|
||||
*
|
||||
* The function calculates the ellipse that fits (in a least-squares sense) a set of 2D points best of
|
||||
* all. It returns the rotated rectangle in which the ellipse is inscribed. The first algorithm described by @cite Fitzgibbon95
|
||||
* is used. Developer should keep in mind that it is possible that the returned
|
||||
* ellipse/rotatedRect data contains negative indices, due to the data points being close to the
|
||||
* border of the containing Mat element.
|
||||
*
|
||||
* @param points Input 2D point set, stored in std::vector\<\> or Mat
|
||||
*
|
||||
* @note Input point types are @ref Point2i or @ref Point2f and at least 5 points are required.
|
||||
* @note @ref getClosestEllipsePoints function can be used to compute the ellipse fitting error.
|
||||
*/
|
||||
CV_EXPORTS_W RotatedRect fitEllipse( InputArray points );
|
||||
|
||||
/** @brief Fits an ellipse around a set of 2D points.
|
||||
*
|
||||
* The function calculates the ellipse that fits a set of 2D points.
|
||||
* It returns the rotated rectangle in which the ellipse is inscribed.
|
||||
* The Approximate Mean Square (AMS) proposed by @cite Taubin1991 is used.
|
||||
*
|
||||
* For an ellipse, this basis set is \f$ \chi= \left(x^2, x y, y^2, x, y, 1\right) \f$,
|
||||
* which is a set of six free coefficients \f$ A^T=\left\{A_{\text{xx}},A_{\text{xy}},A_{\text{yy}},A_x,A_y,A_0\right\} \f$.
|
||||
* However, to specify an ellipse, all that is needed is five numbers; the major and minor axes lengths \f$ (a,b) \f$,
|
||||
* the position \f$ (x_0,y_0) \f$, and the orientation \f$ \theta \f$. This is because the basis set includes lines,
|
||||
* quadratics, parabolic and hyperbolic functions as well as elliptical functions as possible fits.
|
||||
* If the fit is found to be a parabolic or hyperbolic function then the standard #fitEllipse method is used.
|
||||
* The AMS method restricts the fit to parabolic, hyperbolic and elliptical curves
|
||||
* by imposing the condition that \f$ A^T ( D_x^T D_x + D_y^T D_y) A = 1 \f$ where
|
||||
* the matrices \f$ Dx \f$ and \f$ Dy \f$ are the partial derivatives of the design matrix \f$ D \f$ with
|
||||
* respect to x and y. The matrices are formed row by row applying the following to
|
||||
* each of the points in the set:
|
||||
* \f{align*}{
|
||||
* D(i,:)&=\left\{x_i^2, x_i y_i, y_i^2, x_i, y_i, 1\right\} &
|
||||
* D_x(i,:)&=\left\{2 x_i,y_i,0,1,0,0\right\} &
|
||||
* D_y(i,:)&=\left\{0,x_i,2 y_i,0,1,0\right\}
|
||||
* \f}
|
||||
* The AMS method minimizes the cost function
|
||||
* \f{equation*}{
|
||||
* \epsilon ^2=\frac{ A^T D^T D A }{ A^T (D_x^T D_x + D_y^T D_y) A^T }
|
||||
* \f}
|
||||
*
|
||||
* The minimum cost is found by solving the generalized eigenvalue problem.
|
||||
*
|
||||
* \f{equation*}{
|
||||
* D^T D A = \lambda \left( D_x^T D_x + D_y^T D_y\right) A
|
||||
* \f}
|
||||
*
|
||||
* @param points Input 2D point set, stored in std::vector\<\> or Mat
|
||||
*
|
||||
* @note Input point types are @ref Point2i or @ref Point2f and at least 5 points are required.
|
||||
* @note @ref getClosestEllipsePoints function can be used to compute the ellipse fitting error.
|
||||
*/
|
||||
CV_EXPORTS_W RotatedRect fitEllipseAMS( InputArray points );
|
||||
|
||||
|
||||
/** @brief Fits an ellipse around a set of 2D points.
|
||||
*
|
||||
* The function calculates the ellipse that fits a set of 2D points.
|
||||
* It returns the rotated rectangle in which the ellipse is inscribed.
|
||||
* The Direct least square (Direct) method by @cite oy1998NumericallySD is used.
|
||||
*
|
||||
* For an ellipse, this basis set is \f$ \chi= \left(x^2, x y, y^2, x, y, 1\right) \f$,
|
||||
* which is a set of six free coefficients \f$ A^T=\left\{A_{\text{xx}},A_{\text{xy}},A_{\text{yy}},A_x,A_y,A_0\right\} \f$.
|
||||
* However, to specify an ellipse, all that is needed is five numbers; the major and minor axes lengths \f$ (a,b) \f$,
|
||||
* the position \f$ (x_0,y_0) \f$, and the orientation \f$ \theta \f$. This is because the basis set includes lines,
|
||||
* quadratics, parabolic and hyperbolic functions as well as elliptical functions as possible fits.
|
||||
* The Direct method confines the fit to ellipses by ensuring that \f$ 4 A_{xx} A_{yy}- A_{xy}^2 > 0 \f$.
|
||||
* The condition imposed is that \f$ 4 A_{xx} A_{yy}- A_{xy}^2=1 \f$ which satisfies the inequality
|
||||
* and as the coefficients can be arbitrarily scaled is not overly restrictive.
|
||||
*
|
||||
* \f{equation*}{
|
||||
* \epsilon ^2= A^T D^T D A \quad \text{with} \quad A^T C A =1 \quad \text{and} \quad C=\left(\begin{matrix}
|
||||
* 0 & 0 & 2 & 0 & 0 & 0 \\
|
||||
* 0 & -1 & 0 & 0 & 0 & 0 \\
|
||||
* 2 & 0 & 0 & 0 & 0 & 0 \\
|
||||
* 0 & 0 & 0 & 0 & 0 & 0 \\
|
||||
* 0 & 0 & 0 & 0 & 0 & 0 \\
|
||||
* 0 & 0 & 0 & 0 & 0 & 0
|
||||
* \end{matrix} \right)
|
||||
* \f}
|
||||
*
|
||||
* The minimum cost is found by solving the generalized eigenvalue problem.
|
||||
*
|
||||
* \f{equation*}{
|
||||
* D^T D A = \lambda \left( C\right) A
|
||||
* \f}
|
||||
*
|
||||
* The system produces only one positive eigenvalue \f$ \lambda\f$ which is chosen as the solution
|
||||
* with its eigenvector \f$\mathbf{u}\f$. These are used to find the coefficients
|
||||
*
|
||||
* \f{equation*}{
|
||||
* A = \sqrt{\frac{1}{\mathbf{u}^T C \mathbf{u}}} \mathbf{u}
|
||||
* \f}
|
||||
* The scaling factor guarantees that \f$A^T C A =1\f$.
|
||||
*
|
||||
* @param points Input 2D point set, stored in std::vector\<\> or Mat
|
||||
*
|
||||
* @note Input point types are @ref Point2i or @ref Point2f and at least 5 points are required.
|
||||
* @note @ref getClosestEllipsePoints function can be used to compute the ellipse fitting error.
|
||||
*/
|
||||
CV_EXPORTS_W RotatedRect fitEllipseDirect( InputArray points );
|
||||
|
||||
/** @example samples/python/snippets/fitline.py
|
||||
* An example for fitting line in python
|
||||
*/
|
||||
|
||||
/** @brief Compute for each 2d point the nearest 2d point located on a given ellipse.
|
||||
*
|
||||
* The function computes the nearest 2d location on a given ellipse for a vector of 2d points and is based on @cite Chatfield2017 code.
|
||||
* This function can be used to compute for instance the ellipse fitting error.
|
||||
*
|
||||
* @param ellipse_params Ellipse parameters
|
||||
* @param points Input 2d points
|
||||
* @param closest_pts For each 2d point, their corresponding closest 2d point located on a given ellipse
|
||||
*
|
||||
* @note Input point types are @ref Point2i or @ref Point2f
|
||||
* @see fitEllipse, fitEllipseAMS, fitEllipseDirect
|
||||
*/
|
||||
CV_EXPORTS_W void getClosestEllipsePoints( const RotatedRect& ellipse_params, InputArray points, OutputArray closest_pts );
|
||||
|
||||
/** @brief Fits a line to a 2D or 3D point set.
|
||||
*
|
||||
* The function fitLine fits a line to a 2D or 3D point set by minimizing \f$\sum_i \rho(r_i)\f$ where
|
||||
* \f$r_i\f$ is a distance between the \f$i^{th}\f$ point, the line and \f$\rho(r)\f$ is a distance function, one
|
||||
* of the following:
|
||||
* - DIST_L2
|
||||
* \f[\rho (r) = r^2/2 \quad \text{(the simplest and the fastest least-squares method)}\f]
|
||||
* - DIST_L1
|
||||
* \f[\rho (r) = r\f]
|
||||
* - DIST_L12
|
||||
* \f[\rho (r) = 2 \cdot ( \sqrt{1 + \frac{r^2}{2}} - 1)\f]
|
||||
* - DIST_FAIR
|
||||
* \f[\rho \left (r \right ) = C^2 \cdot \left ( \frac{r}{C} - \log{\left(1 + \frac{r}{C}\right)} \right ) \quad \text{where} \quad C=1.3998\f]
|
||||
* - DIST_WELSCH
|
||||
* \f[\rho \left (r \right ) = \frac{C^2}{2} \cdot \left ( 1 - \exp{\left(-\left(\frac{r}{C}\right)^2\right)} \right ) \quad \text{where} \quad C=2.9846\f]
|
||||
* - DIST_HUBER
|
||||
* \f[\rho (r) = \fork{r^2/2}{if \(r < C\)}{C \cdot (r-C/2)}{otherwise} \quad \text{where} \quad C=1.345\f]
|
||||
*
|
||||
* The algorithm is based on the M-estimator ( <https://en.wikipedia.org/wiki/M-estimator> ) technique
|
||||
* that iteratively fits the line using the weighted least-squares algorithm. After each iteration the
|
||||
* weights \f$w_i\f$ are adjusted to be inversely proportional to \f$\rho(r_i)\f$ .
|
||||
*
|
||||
* @param points Input vector of 2D or 3D points, stored in std::vector\<\> or Mat.
|
||||
* @param line Output line parameters. In case of 2D fitting, it should be a vector of 4 elements
|
||||
* (like Vec4f) - (vx, vy, x0, y0), where (vx, vy) is a normalized vector collinear to the line and
|
||||
* (x0, y0) is a point on the line. In case of 3D fitting, it should be a vector of 6 elements (like
|
||||
* Vec6f) - (vx, vy, vz, x0, y0, z0), where (vx, vy, vz) is a normalized vector collinear to the line
|
||||
* and (x0, y0, z0) is a point on the line.
|
||||
* @param distType Distance used by the M-estimator, see #DistanceTypes
|
||||
* @param param Numerical parameter ( C ) for some types of distances. If it is 0, an optimal value
|
||||
* is chosen.
|
||||
* @param reps Sufficient accuracy for the radius (distance between the coordinate origin and the line).
|
||||
* @param aeps Sufficient accuracy for the angle. 0.01 would be a good default value for reps and aeps.
|
||||
*/
|
||||
CV_EXPORTS_W void fitLine( InputArray points, OutputArray line, int distType,
|
||||
double param, double reps, double aeps );
|
||||
|
||||
/** @brief Performs a point-in-contour test.
|
||||
*
|
||||
* The function determines whether the point is inside a contour, outside, or lies on an edge (or
|
||||
* coincides with a vertex). It returns positive (inside), negative (outside), or zero (on an edge)
|
||||
* value, correspondingly. When measureDist=false , the return value is +1, -1, and 0, respectively.
|
||||
* Otherwise, the return value is a signed distance between the point and the nearest contour edge.
|
||||
*
|
||||
* See below a sample output of the function where each image pixel is tested against the contour:
|
||||
*
|
||||
* 
|
||||
*
|
||||
* @param contour Input contour.
|
||||
* @param pt Point tested against the contour.
|
||||
* @param measureDist If true, the function estimates the signed distance from the point to the
|
||||
* nearest contour edge. Otherwise, the function only checks if the point is inside a contour or not.
|
||||
*/
|
||||
CV_EXPORTS_W double pointPolygonTest( InputArray contour, Point2f pt, bool measureDist );
|
||||
|
||||
/** @brief Finds out if there is any intersection between two rotated rectangles.
|
||||
*
|
||||
* If there is then the vertices of the intersecting region are returned as well.
|
||||
*
|
||||
* Below are some examples of intersection configurations. The hatched pattern indicates the
|
||||
* intersecting region and the red vertices are returned by the function.
|
||||
*
|
||||
* 
|
||||
*
|
||||
* @param rect1 First rectangle
|
||||
* @param rect2 Second rectangle
|
||||
* @param intersectingRegion The output array of the vertices of the intersecting region. It returns
|
||||
* at most 8 vertices. Stored as std::vector\<cv::Point2f\> or cv::Mat as Mx1 of type CV_32FC2.
|
||||
* @returns One of #RectanglesIntersectTypes
|
||||
*/
|
||||
CV_EXPORTS_W int rotatedRectangleIntersection( const RotatedRect& rect1, const RotatedRect& rect2, OutputArray intersectingRegion );
|
||||
|
||||
} // namespace cv
|
||||
|
||||
#endif // OPENCV_2D_HPP
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,181 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html
|
||||
|
||||
#ifndef OPENCV_3D_DEPTH_HPP
|
||||
#define OPENCV_3D_DEPTH_HPP
|
||||
|
||||
#include <opencv2/core.hpp>
|
||||
#include <limits>
|
||||
|
||||
namespace cv
|
||||
{
|
||||
//! @addtogroup rgbd
|
||||
//! @{
|
||||
|
||||
/** Object that can compute the normals in an image.
|
||||
* It is an object as it can cache data for speed efficiency
|
||||
* The implemented methods are either:
|
||||
* - FALS (the fastest) and SRI from
|
||||
* ``Fast and Accurate Computation of Surface Normals from Range Images``
|
||||
* by H. Badino, D. Huber, Y. Park and T. Kanade
|
||||
* - the normals with bilateral filtering on a depth image from
|
||||
* ``Gradient Response Maps for Real-Time Detection of Texture-Less Objects``
|
||||
* by S. Hinterstoisser, C. Cagniart, S. Ilic, P. Sturm, N. Navab, P. Fua, and V. Lepetit
|
||||
*/
|
||||
class CV_EXPORTS_W RgbdNormals
|
||||
{
|
||||
public:
|
||||
enum RgbdNormalsMethod
|
||||
{
|
||||
RGBD_NORMALS_METHOD_FALS = 0,
|
||||
RGBD_NORMALS_METHOD_LINEMOD = 1,
|
||||
RGBD_NORMALS_METHOD_SRI = 2,
|
||||
RGBD_NORMALS_METHOD_CROSS_PRODUCT = 3
|
||||
};
|
||||
|
||||
RgbdNormals() { }
|
||||
virtual ~RgbdNormals() { }
|
||||
|
||||
/** Creates new RgbdNormals object
|
||||
* @param rows the number of rows of the depth image normals will be computed on
|
||||
* @param cols the number of cols of the depth image normals will be computed on
|
||||
* @param depth the depth of the normals (only CV_32F or CV_64F)
|
||||
* @param K the calibration matrix to use
|
||||
* @param window_size the window size to compute the normals: can only be 1,3,5 or 7
|
||||
* @param diff_threshold threshold in depth difference, used in LINEMOD algirithm
|
||||
* @param method one of the methods to use: RGBD_NORMALS_METHOD_SRI, RGBD_NORMALS_METHOD_FALS
|
||||
*/
|
||||
CV_WRAP static Ptr<RgbdNormals> create(int rows = 0, int cols = 0, int depth = 0, InputArray K = noArray(), int window_size = 5,
|
||||
float diff_threshold = 50.f,
|
||||
RgbdNormals::RgbdNormalsMethod method = RgbdNormals::RgbdNormalsMethod::RGBD_NORMALS_METHOD_FALS);
|
||||
|
||||
/** Given a set of 3d points in a depth image, compute the normals at each point.
|
||||
* @param points a rows x cols x 3 matrix of CV_32F/CV64F or a rows x cols x 1 CV_U16S
|
||||
* @param normals a rows x cols x 3 matrix
|
||||
*/
|
||||
CV_WRAP virtual void apply(InputArray points, OutputArray normals) const = 0;
|
||||
|
||||
/** Prepares cached data required for calculation
|
||||
* If not called by user, called automatically at first calculation
|
||||
*/
|
||||
CV_WRAP virtual void cache() const = 0;
|
||||
|
||||
CV_WRAP virtual int getRows() const = 0;
|
||||
CV_WRAP virtual void setRows(int val) = 0;
|
||||
CV_WRAP virtual int getCols() const = 0;
|
||||
CV_WRAP virtual void setCols(int val) = 0;
|
||||
CV_WRAP virtual int getWindowSize() const = 0;
|
||||
CV_WRAP virtual void setWindowSize(int val) = 0;
|
||||
CV_WRAP virtual int getDepth() const = 0;
|
||||
CV_WRAP virtual void getK(OutputArray val) const = 0;
|
||||
CV_WRAP virtual void setK(InputArray val) = 0;
|
||||
CV_WRAP virtual RgbdNormals::RgbdNormalsMethod getMethod() const = 0;
|
||||
};
|
||||
|
||||
|
||||
/** Registers depth data to an external camera
|
||||
* Registration is performed by creating a depth cloud, transforming the cloud by
|
||||
* the rigid body transformation between the cameras, and then projecting the
|
||||
* transformed points into the RGB camera.
|
||||
*
|
||||
* uv_rgb = K_rgb * [R | t] * z * inv(K_ir) * uv_ir
|
||||
*
|
||||
* Currently does not check for negative depth values.
|
||||
*
|
||||
* @param unregisteredCameraMatrix the camera matrix of the depth camera
|
||||
* @param registeredCameraMatrix the camera matrix of the external camera
|
||||
* @param registeredDistCoeffs the distortion coefficients of the external camera
|
||||
* @param Rt the rigid body transform between the cameras. Transforms points from depth camera frame to external camera frame.
|
||||
* @param unregisteredDepth the input depth data
|
||||
* @param outputImagePlaneSize the image plane dimensions of the external camera (width, height)
|
||||
* @param registeredDepth the result of transforming the depth into the external camera
|
||||
* @param depthDilation whether or not the depth is dilated to avoid holes and occlusion errors (optional)
|
||||
*/
|
||||
CV_EXPORTS_W void registerDepth(InputArray unregisteredCameraMatrix, InputArray registeredCameraMatrix, InputArray registeredDistCoeffs,
|
||||
InputArray Rt, InputArray unregisteredDepth, const Size& outputImagePlaneSize,
|
||||
OutputArray registeredDepth, bool depthDilation=false);
|
||||
|
||||
/**
|
||||
* @param depth the depth image
|
||||
* @param in_K
|
||||
* @param in_points the list of xy coordinates
|
||||
* @param points3d the resulting 3d points (point is represented by 4 chanels value [x, y, z, 0])
|
||||
*/
|
||||
CV_EXPORTS_W void depthTo3dSparse(InputArray depth, InputArray in_K, InputArray in_points, OutputArray points3d);
|
||||
|
||||
/** Converts a depth image to 3d points. If the mask is empty then the resulting array has the same dimensions as `depth`,
|
||||
* otherwise it is 1d vector containing mask-enabled values only.
|
||||
* The coordinate system is x pointing left, y down and z away from the camera
|
||||
* @param depth the depth image (if given as short int CV_U, it is assumed to be the depth in millimeters
|
||||
* (as done with the Microsoft Kinect), otherwise, if given as CV_32F or CV_64F, it is assumed in meters)
|
||||
* @param K The calibration matrix
|
||||
* @param points3d the resulting 3d points (point is represented by 4 channels value [x, y, z, 0]). They are of the same depth as `depth` if it is CV_32F or CV_64F, and the
|
||||
* depth of `K` if `depth` is of depth CV_16U or CV_16S
|
||||
* @param mask the mask of the points to consider (can be empty)
|
||||
*/
|
||||
CV_EXPORTS_W void depthTo3d(InputArray depth, InputArray K, OutputArray points3d, InputArray mask = noArray());
|
||||
|
||||
/** If the input image is of type CV_16UC1 (like the Kinect one), the image is converted to floats, divided
|
||||
* by depth_factor to get a depth in meters, and the values 0 are converted to std::numeric_limits<float>::quiet_NaN()
|
||||
* Otherwise, the image is simply converted to floats
|
||||
* @param in the depth image (if given as short int CV_U, it is assumed to be the depth in millimeters
|
||||
* (as done with the Microsoft Kinect), it is assumed in meters)
|
||||
* @param type the desired output depth (CV_32F or CV_64F)
|
||||
* @param out The rescaled float depth image
|
||||
* @param depth_factor (optional) factor by which depth is converted to distance (by default = 1000.0 for Kinect sensor)
|
||||
*/
|
||||
CV_EXPORTS_W void rescaleDepth(InputArray in, int type, OutputArray out, double depth_factor = 1000.0);
|
||||
|
||||
/** Warps depth or RGB-D image by reprojecting it in 3d, applying Rt transformation
|
||||
* and then projecting it back onto the image plane.
|
||||
* This function can be used to visualize the results of the Odometry algorithm.
|
||||
* @param depth Depth data, should be 1-channel CV_16U, CV_16S, CV_32F or CV_64F
|
||||
* @param image RGB image (optional), should be 1-, 3- or 4-channel CV_8U
|
||||
* @param mask Mask of used pixels (optional), should be CV_8UC1, CV_8SC1 or CV_BoolC1
|
||||
* @param Rt Rotation+translation matrix (3x4 or 4x4) to be applied to depth points
|
||||
* @param cameraMatrix Camera intrinsics matrix (3x3)
|
||||
* @param warpedDepth The warped depth data (optional)
|
||||
* @param warpedImage The warped RGB image (optional)
|
||||
* @param warpedMask The mask of valid pixels in warped image (optional)
|
||||
*/
|
||||
CV_EXPORTS_W void warpFrame(InputArray depth, InputArray image, InputArray mask, InputArray Rt, InputArray cameraMatrix,
|
||||
OutputArray warpedDepth = noArray(), OutputArray warpedImage = noArray(), OutputArray warpedMask = noArray());
|
||||
|
||||
enum RgbdPlaneMethod
|
||||
{
|
||||
RGBD_PLANE_METHOD_DEFAULT
|
||||
};
|
||||
|
||||
/** Find the planes in a depth image
|
||||
* @param points3d the 3d points organized like the depth image: rows x cols with 3 channels
|
||||
* @param normals the normals for every point in the depth image; optional, can be empty
|
||||
* @param mask An image where each pixel is labeled with the plane it belongs to
|
||||
* and 255 if it does not belong to any plane
|
||||
* @param plane_coefficients the coefficients of the corresponding planes (a,b,c,d) such that ax+by+cz+d=0, norm(a,b,c)=1
|
||||
* and c < 0 (so that the normal points towards the camera)
|
||||
* @param block_size The size of the blocks to look at for a stable MSE
|
||||
* @param min_size The minimum size of a cluster to be considered a plane
|
||||
* @param threshold The maximum distance of a point from a plane to belong to it (in meters)
|
||||
* @param sensor_error_a coefficient of the sensor error. 0 by default, use 0.0075 for a Kinect
|
||||
* @param sensor_error_b coefficient of the sensor error. 0 by default
|
||||
* @param sensor_error_c coefficient of the sensor error. 0 by default
|
||||
* @param method The method to use to compute the planes.
|
||||
*/
|
||||
CV_EXPORTS_W void findPlanes(InputArray points3d, InputArray normals, OutputArray mask, OutputArray plane_coefficients,
|
||||
int block_size = 40, int min_size = 40*40, double threshold = 0.01,
|
||||
double sensor_error_a = 0, double sensor_error_b = 0,
|
||||
double sensor_error_c = 0,
|
||||
RgbdPlaneMethod method = RGBD_PLANE_METHOD_DEFAULT);
|
||||
|
||||
|
||||
|
||||
// TODO Depth interpolation
|
||||
// Curvature
|
||||
// Get rescaleDepth return dubles if asked for
|
||||
|
||||
//! @}
|
||||
|
||||
} /* namespace cv */
|
||||
|
||||
#endif // include guard
|
||||
@@ -0,0 +1,19 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html
|
||||
|
||||
#ifndef OPENCV_3D_DETAIL_KINFU_FRAME_HPP
|
||||
#define OPENCV_3D_DETAIL_KINFU_FRAME_HPP
|
||||
|
||||
#include <opencv2/core/affine.hpp>
|
||||
|
||||
namespace cv {
|
||||
namespace detail {
|
||||
|
||||
CV_EXPORTS void renderPointsNormals(InputArray _points, InputArray _normals, OutputArray image, cv::Vec3f lightLoc);
|
||||
CV_EXPORTS void renderPointsNormalsColors(InputArray _points, InputArray _normals, InputArray _colors, OutputArray image);
|
||||
|
||||
} // namespace detail
|
||||
} // namespace cv
|
||||
|
||||
#endif // include guard
|
||||
@@ -0,0 +1,148 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html
|
||||
|
||||
#ifndef OPENCV_3D_DETAIL_OPTIMIZER_HPP
|
||||
#define OPENCV_3D_DETAIL_OPTIMIZER_HPP
|
||||
|
||||
#include "opencv2/core/affine.hpp"
|
||||
#include "opencv2/core/quaternion.hpp"
|
||||
#include "opencv2/geometry/3d.hpp"
|
||||
|
||||
namespace cv
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
|
||||
/*
|
||||
This class provides functions required for Levenberg-Marquadt algorithm implementation.
|
||||
See LevMarqBase::optimize() source code for details.
|
||||
*/
|
||||
class CV_EXPORTS LevMarqBackend
|
||||
{
|
||||
public:
|
||||
virtual ~LevMarqBackend() { }
|
||||
|
||||
// enables geodesic acceleration support in a backend, returns true on success
|
||||
virtual bool enableGeo() = 0;
|
||||
|
||||
// calculates an energy and/or jacobian at probe param vector
|
||||
virtual bool calcFunc(double& energy, bool calcEnergy = true, bool calcJacobian = false) = 0;
|
||||
|
||||
// adds x to current variables and writes the sum to probe var
|
||||
// or to geodesic acceleration var if geo flag is set
|
||||
virtual void currentOplusX(const Mat_<double>& x, bool geo = false) = 0;
|
||||
|
||||
// allocates jtj, jtb and other resources for objective function calculation, sets probeX to current X
|
||||
virtual void prepareVars() = 0;
|
||||
// returns a J^T*b vector (aka gradient)
|
||||
virtual const Mat_<double> getJtb() = 0;
|
||||
// returns a J^T*J diagonal vector
|
||||
virtual const Mat_<double> getDiag() = 0;
|
||||
// sets a J^T*J diagonal
|
||||
virtual void setDiag(const Mat_<double>& d) = 0;
|
||||
// performs jacobi scaling if the option is turned on
|
||||
virtual void doJacobiScaling(const Mat_<double>& di) = 0;
|
||||
|
||||
// decomposes LevMarq matrix before solution
|
||||
virtual bool decompose() = 0;
|
||||
// solves LevMarq equation (J^T*J + lmdiag) * x = -right for current iteration using existing decomposition
|
||||
// right can be equal to J^T*b for LevMarq equation or J^T*rvv for geodesic acceleration equation
|
||||
virtual bool solveDecomposed(const Mat_<double>& right, Mat_<double>& x) = 0;
|
||||
|
||||
// calculates J^T*f(geo) where geo is geodesic acceleration variable
|
||||
// this is used for J^T*rvv calculation for geodesic acceleration
|
||||
// calculates J^T*rvv where rvv is second directional derivative of the function in direction v
|
||||
// rvv = (f(x0 + v*h) - f(x0))/h - J*v)/h
|
||||
// where v is a LevMarq equation solution
|
||||
virtual bool calcJtbv(Mat_<double>& jtbv) = 0;
|
||||
|
||||
// sets current params vector to probe params
|
||||
virtual void acceptProbe() = 0;
|
||||
};
|
||||
|
||||
/** @brief Base class for Levenberg-Marquadt solvers.
|
||||
|
||||
This class can be used for general local optimization using sparse linear solvers, exponential param update or fixed variables
|
||||
implemented in child classes.
|
||||
This base class does not depend on a type, layout or a group structure of a param vector or an objective function jacobian.
|
||||
A child class should provide a storage for that data and implement all virtual member functions that process it.
|
||||
This class does not support fixed/masked variables, this should also be implemented in child classes.
|
||||
*/
|
||||
class CV_EXPORTS LevMarqBase
|
||||
{
|
||||
public:
|
||||
virtual ~LevMarqBase() { }
|
||||
|
||||
// runs optimization using given termination conditions
|
||||
virtual LevMarq::Report optimize();
|
||||
|
||||
LevMarqBase(const Ptr<LevMarqBackend>& backend_, const LevMarq::Settings& settings_):
|
||||
backend(backend_), settings(settings_)
|
||||
{ }
|
||||
|
||||
Ptr<LevMarqBackend> backend;
|
||||
LevMarq::Settings settings;
|
||||
};
|
||||
|
||||
|
||||
// ATTENTION! This class is used internally in Large KinFu.
|
||||
// It has been pushed to publicly available headers for tests only.
|
||||
// Source compatibility of this API is not guaranteed in the future.
|
||||
|
||||
// This class provides tools to solve so-called pose graph problem often arisen in SLAM problems
|
||||
// The pose graph format, cost function and optimization techniques
|
||||
// repeat the ones used in Ceres 3D Pose Graph Optimization:
|
||||
// http://ceres-solver.org/nnls_tutorial.html#other-examples, pose_graph_3d.cc bullet
|
||||
class CV_EXPORTS_W PoseGraph
|
||||
{
|
||||
public:
|
||||
static Ptr<PoseGraph> create();
|
||||
virtual ~PoseGraph();
|
||||
|
||||
// Node may have any id >= 0
|
||||
virtual void addNode(size_t _nodeId, const Affine3d& _pose, bool fixed) = 0;
|
||||
virtual bool isNodeExist(size_t nodeId) const = 0;
|
||||
virtual bool setNodeFixed(size_t nodeId, bool fixed) = 0;
|
||||
virtual bool isNodeFixed(size_t nodeId) const = 0;
|
||||
virtual Affine3d getNodePose(size_t nodeId) const = 0;
|
||||
virtual std::vector<size_t> getNodesIds() const = 0;
|
||||
virtual size_t getNumNodes() const = 0;
|
||||
|
||||
// Edges have consequent indices starting from 0
|
||||
virtual void addEdge(size_t _sourceNodeId, size_t _targetNodeId, const Affine3f& _transformation,
|
||||
const Matx66f& _information = Matx66f::eye()) = 0;
|
||||
virtual size_t getEdgeStart(size_t i) const = 0;
|
||||
virtual size_t getEdgeEnd(size_t i) const = 0;
|
||||
virtual Affine3d getEdgePose(size_t i) const = 0;
|
||||
virtual Matx66f getEdgeInfo(size_t i) const = 0;
|
||||
virtual size_t getNumEdges() const = 0;
|
||||
|
||||
// checks if graph is connected and each edge connects exactly 2 nodes
|
||||
virtual bool isValid() const = 0;
|
||||
|
||||
// Calculates an initial pose estimate using the Minimum Spanning Tree (Prim's MST) algorithm.
|
||||
// The result serves as a starting point for further optimization.
|
||||
// Edge weights are calculated as:
|
||||
// weight = translationNorm + lambda * rotationAngle
|
||||
// The default lambda value (0.485) was empirically chosen based on its impact on optimizer performance,
|
||||
// but can/should be tuned for different datasets.
|
||||
virtual void initializePosesWithMST(double lambda = 0.485) = 0;
|
||||
|
||||
// creates an optimizer with user-defined settings and returns a pointer on it
|
||||
virtual Ptr<LevMarqBase> createOptimizer(const LevMarq::Settings& settings) = 0;
|
||||
// creates an optimizer with default settings and returns a pointer on it
|
||||
virtual Ptr<LevMarqBase> createOptimizer() = 0;
|
||||
|
||||
// Creates an optimizer (with default settings) if it wasn't created before and runs it
|
||||
// Returns number of iterations elapsed or -1 if failed to optimize
|
||||
virtual LevMarq::Report optimize() = 0;
|
||||
|
||||
// calculate cost function based on current nodes parameters
|
||||
virtual double calcEnergy() const = 0;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
} // namespace cv
|
||||
|
||||
#endif // include guard
|
||||
@@ -0,0 +1,558 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html
|
||||
|
||||
#ifndef OPENCV_3D_DETAIL_SUBMAP_HPP
|
||||
#define OPENCV_3D_DETAIL_SUBMAP_HPP
|
||||
|
||||
#include <opencv2/core.hpp>
|
||||
#include <opencv2/core/affine.hpp>
|
||||
#include "opencv2/geometry/detail/optimizer.hpp"
|
||||
|
||||
//TODO: remove it when it is rewritten to robust pose graph
|
||||
#include "opencv2/core/dualquaternion.hpp"
|
||||
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
|
||||
|
||||
namespace cv
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
template<typename MatType>
|
||||
class Submap
|
||||
{
|
||||
public:
|
||||
struct PoseConstraint
|
||||
{
|
||||
Affine3f estimatedPose;
|
||||
int weight;
|
||||
|
||||
PoseConstraint() : weight(0){};
|
||||
|
||||
void accumulatePose(const Affine3f& _pose, int _weight = 1)
|
||||
{
|
||||
DualQuatf accPose = DualQuatf::createFromAffine3(estimatedPose) * float(weight) + DualQuatf::createFromAffine3(_pose) * float(_weight);
|
||||
weight += _weight;
|
||||
accPose = accPose / float(weight);
|
||||
estimatedPose = accPose.toAffine3();
|
||||
}
|
||||
};
|
||||
typedef std::map<int, PoseConstraint> Constraints;
|
||||
|
||||
Submap(int _id, const VolumeSettings& settings, const cv::Affine3f& _pose = cv::Affine3f::Identity(),
|
||||
int _startFrameId = 0)
|
||||
: id(_id), pose(_pose), cameraPose(Affine3f::Identity()), startFrameId(_startFrameId),
|
||||
volume(VolumeType::HashTSDF, settings)
|
||||
{ }
|
||||
virtual ~Submap() = default;
|
||||
|
||||
virtual void integrate(InputArray _depth, const int currframeId);
|
||||
virtual void raycast(const cv::Affine3f& cameraPose, cv::Size frameSize, cv::Matx33f K,
|
||||
OutputArray points = noArray(), OutputArray normals = noArray());
|
||||
|
||||
virtual int getTotalAllocatedBlocks() const { return int(volume.getTotalVolumeUnits()); };
|
||||
virtual int getVisibleBlocks(int currFrameId) const
|
||||
{
|
||||
CV_Assert(currFrameId >= startFrameId);
|
||||
//return volume.getVisibleBlocks(currFrameId, FRAME_VISIBILITY_THRESHOLD);
|
||||
return volume.getVisibleBlocks();
|
||||
|
||||
}
|
||||
|
||||
float calcVisibilityRatio(int currFrameId) const
|
||||
{
|
||||
int allocate_blocks = getTotalAllocatedBlocks();
|
||||
int visible_blocks = getVisibleBlocks(currFrameId);
|
||||
return float(visible_blocks) / float(allocate_blocks);
|
||||
}
|
||||
|
||||
// Adding new Edge for Loop Closure Detection. Return true or false to indicate whether adding success.
|
||||
bool addEdgeToSubmap(const int tarSubmapID, const Affine3f& tarPose);
|
||||
|
||||
//! TODO: Possibly useless
|
||||
virtual void setStartFrameId(int _startFrameId) { startFrameId = _startFrameId; };
|
||||
virtual void setStopFrameId(int _stopFrameId) { stopFrameId = _stopFrameId; };
|
||||
|
||||
void composeCameraPose(const cv::Affine3f& _relativePose) { cameraPose = cameraPose * _relativePose; }
|
||||
PoseConstraint& getConstraint(const int _id)
|
||||
{
|
||||
//! Creates constraints if doesn't exist yet
|
||||
return constraints[_id];
|
||||
}
|
||||
|
||||
public:
|
||||
const int id;
|
||||
cv::Affine3f pose;
|
||||
cv::Affine3f cameraPose;
|
||||
Constraints constraints;
|
||||
|
||||
int startFrameId;
|
||||
int stopFrameId;
|
||||
//! TODO: Should we support submaps for regular volumes?
|
||||
static constexpr int FRAME_VISIBILITY_THRESHOLD = 5;
|
||||
|
||||
//! TODO: Add support for GPU arrays (UMat)
|
||||
OdometryFrame frame;
|
||||
OdometryFrame renderFrame;
|
||||
|
||||
Volume volume;
|
||||
};
|
||||
|
||||
template<typename MatType>
|
||||
|
||||
void Submap<MatType>::integrate(InputArray _depth, const int currFrameId)
|
||||
{
|
||||
CV_Assert(currFrameId >= startFrameId);
|
||||
volume.integrate(_depth, cameraPose.matrix);
|
||||
}
|
||||
|
||||
template<typename MatType>
|
||||
void Submap<MatType>::raycast(const cv::Affine3f& _cameraPose, cv::Size frameSize, cv::Matx33f K,
|
||||
OutputArray points, OutputArray normals)
|
||||
{
|
||||
if (!points.needed() && !normals.needed())
|
||||
{
|
||||
MatType pts, nrm;
|
||||
//TODO: get depth instead of pts from raycast
|
||||
volume.raycast(_cameraPose.matrix, frameSize.height, frameSize.width, K, pts, nrm);
|
||||
|
||||
std::vector<MatType> pch(3);
|
||||
split(pts, pch);
|
||||
|
||||
renderFrame = frame;
|
||||
|
||||
frame = OdometryFrame(pch[2]);
|
||||
}
|
||||
else
|
||||
{
|
||||
volume.raycast(_cameraPose.matrix, frameSize.height, frameSize.width, K, points, normals);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename MatType>
|
||||
bool Submap<MatType>::addEdgeToSubmap(const int tarSubmapID, const Affine3f& tarPose)
|
||||
{
|
||||
auto iter = constraints.find(tarSubmapID);
|
||||
|
||||
// if there is NO edge of currSubmap to tarSubmap.
|
||||
if(iter == constraints.end())
|
||||
{
|
||||
// Frome pose to tarPose transformation
|
||||
Affine3f estimatePose = tarPose * pose.inv();
|
||||
|
||||
// Create new Edge.
|
||||
PoseConstraint& preConstrain = getConstraint(tarSubmapID);
|
||||
preConstrain.accumulatePose(estimatePose, 1);
|
||||
|
||||
return true;
|
||||
} else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief: Manages all the created submaps for a particular scene
|
||||
*/
|
||||
template<typename MatType>
|
||||
class SubmapManager
|
||||
{
|
||||
public:
|
||||
enum class Type
|
||||
{
|
||||
NEW = 0,
|
||||
CURRENT = 1,
|
||||
RELOCALISATION = 2,
|
||||
LOOP_CLOSURE = 3,
|
||||
LOST = 4
|
||||
};
|
||||
|
||||
struct ActiveSubmapData
|
||||
{
|
||||
Type type;
|
||||
std::vector<Affine3f> constraints;
|
||||
int trackingAttempts;
|
||||
};
|
||||
|
||||
typedef Submap<MatType> SubmapT;
|
||||
typedef std::map<int, Ptr<SubmapT>> IdToSubmapPtr;
|
||||
typedef std::unordered_map<int, ActiveSubmapData> IdToActiveSubmaps;
|
||||
|
||||
explicit SubmapManager(const VolumeSettings& _volumeSettings) : volumeSettings(_volumeSettings) {}
|
||||
virtual ~SubmapManager() = default;
|
||||
|
||||
void reset() { submapList.clear(); };
|
||||
|
||||
bool shouldCreateSubmap(int frameId);
|
||||
bool shouldChangeCurrSubmap(int _frameId, int toSubmapId);
|
||||
|
||||
//! Adds a new submap/volume into the current list of managed/Active submaps
|
||||
int createNewSubmap(bool isCurrentActiveMap, const int currFrameId = 0, const Affine3f& pose = cv::Affine3f::Identity());
|
||||
|
||||
void removeSubmap(int _id);
|
||||
size_t numOfSubmaps(void) const { return submapList.size(); };
|
||||
size_t numOfActiveSubmaps(void) const { return activeSubmaps.size(); };
|
||||
|
||||
Ptr<SubmapT> getSubmap(int _id) const;
|
||||
Ptr<SubmapT> getCurrentSubmap(void) const;
|
||||
|
||||
int estimateConstraint(int fromSubmapId, int toSubmapId, int& inliers, Affine3f& inlierPose);
|
||||
bool updateMap(int frameId, const OdometryFrame& frame);
|
||||
|
||||
bool addEdgeToCurrentSubmap(const int currentSubmapID, const int tarSubmapID);
|
||||
|
||||
Ptr<detail::PoseGraph> MapToPoseGraph();
|
||||
void PoseGraphToMap(const Ptr<detail::PoseGraph>& updatedPoseGraph);
|
||||
|
||||
VolumeSettings volumeSettings;
|
||||
|
||||
std::vector<Ptr<SubmapT>> submapList;
|
||||
IdToActiveSubmaps activeSubmaps;
|
||||
|
||||
Ptr<detail::PoseGraph> poseGraph;
|
||||
};
|
||||
|
||||
template<typename MatType>
|
||||
int SubmapManager<MatType>::createNewSubmap(bool isCurrentMap, int currFrameId, const Affine3f& pose)
|
||||
{
|
||||
int newId = int(submapList.size());
|
||||
|
||||
Ptr<SubmapT> newSubmap = cv::makePtr<SubmapT>(newId, volumeSettings, pose, currFrameId);
|
||||
submapList.push_back(newSubmap);
|
||||
|
||||
ActiveSubmapData newSubmapData;
|
||||
newSubmapData.trackingAttempts = 0;
|
||||
newSubmapData.type = isCurrentMap ? Type::CURRENT : Type::NEW;
|
||||
activeSubmaps[newId] = newSubmapData;
|
||||
|
||||
return newId;
|
||||
}
|
||||
|
||||
template<typename MatType>
|
||||
Ptr<Submap<MatType>> SubmapManager<MatType>::getSubmap(int _id) const
|
||||
{
|
||||
CV_Assert(submapList.size() > 0);
|
||||
CV_Assert(_id >= 0 && _id < int(submapList.size()));
|
||||
return submapList.at(_id);
|
||||
}
|
||||
|
||||
template<typename MatType>
|
||||
Ptr<Submap<MatType>> SubmapManager<MatType>::getCurrentSubmap(void) const
|
||||
{
|
||||
for (const auto& it : activeSubmaps)
|
||||
{
|
||||
if (it.second.type == Type::CURRENT)
|
||||
return getSubmap(it.first);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template<typename MatType>
|
||||
bool SubmapManager<MatType>::shouldCreateSubmap(int currFrameId)
|
||||
{
|
||||
int currSubmapId = -1;
|
||||
for (const auto& it : activeSubmaps)
|
||||
{
|
||||
auto submapData = it.second;
|
||||
// No more than 1 new submap at a time!
|
||||
if (submapData.type == Type::NEW)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (submapData.type == Type::CURRENT)
|
||||
{
|
||||
currSubmapId = it.first;
|
||||
}
|
||||
}
|
||||
//! TODO: This shouldn't be happening? since there should always be one active current submap
|
||||
if (currSubmapId < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Ptr<SubmapT> currSubmap = getSubmap(currSubmapId);
|
||||
float ratio = currSubmap->calcVisibilityRatio(currFrameId);
|
||||
|
||||
//TODO: fix this when a new pose graph is ready
|
||||
// if (ratio < 0.2f)
|
||||
if (ratio < 0.5f)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
template<typename MatType>
|
||||
int SubmapManager<MatType>::estimateConstraint(int fromSubmapId, int toSubmapId, int& inliers, Affine3f& inlierPose)
|
||||
{
|
||||
static constexpr int MAX_ITER = 10;
|
||||
static constexpr float CONVERGE_WEIGHT_THRESHOLD = 0.01f;
|
||||
static constexpr float INLIER_WEIGHT_THRESH = 0.8f;
|
||||
static constexpr int MIN_INLIERS = 10;
|
||||
static constexpr int MAX_TRACKING_ATTEMPTS = 25;
|
||||
|
||||
//! thresh = HUBER_THRESH
|
||||
auto huberWeight = [](float residual, float thresh = 0.1f) -> float {
|
||||
float rAbs = abs(residual);
|
||||
if (rAbs < thresh)
|
||||
return 1.0;
|
||||
float numerator = sqrt(2 * thresh * rAbs - thresh * thresh);
|
||||
return numerator / rAbs;
|
||||
};
|
||||
|
||||
Ptr<SubmapT> fromSubmap = getSubmap(fromSubmapId);
|
||||
Ptr<SubmapT> toSubmap = getSubmap(toSubmapId);
|
||||
ActiveSubmapData& fromSubmapData = activeSubmaps.at(fromSubmapId);
|
||||
|
||||
Affine3f TcameraToFromSubmap = fromSubmap->cameraPose;
|
||||
Affine3f TcameraToToSubmap = toSubmap->cameraPose;
|
||||
|
||||
// FromSubmap -> ToSubmap transform
|
||||
Affine3f candidateConstraint = TcameraToToSubmap * TcameraToFromSubmap.inv();
|
||||
fromSubmapData.trackingAttempts++;
|
||||
fromSubmapData.constraints.push_back(candidateConstraint);
|
||||
|
||||
std::vector<float> weights(fromSubmapData.constraints.size() + 1, 1.0f);
|
||||
|
||||
Affine3f prevConstraint = fromSubmap->getConstraint(toSubmap->id).estimatedPose;
|
||||
int prevWeight = fromSubmap->getConstraint(toSubmap->id).weight;
|
||||
|
||||
// Iterative reweighted least squares with huber threshold to find the inliers in the past observations
|
||||
Vec6f meanConstraint;
|
||||
float sumWeight = 0.0f;
|
||||
for (int i = 0; i < MAX_ITER; i++)
|
||||
{
|
||||
Vec6f constraintVec;
|
||||
for (int j = 0; j < int(weights.size() - 1); j++)
|
||||
{
|
||||
Affine3f currObservation = fromSubmapData.constraints[j];
|
||||
cv::vconcat(currObservation.rvec(), currObservation.translation(), constraintVec);
|
||||
meanConstraint += weights[j] * constraintVec;
|
||||
sumWeight += weights[j];
|
||||
}
|
||||
// Heavier weight given to the estimatedPose
|
||||
cv::vconcat(prevConstraint.rvec(), prevConstraint.translation(), constraintVec);
|
||||
meanConstraint += weights.back() * prevWeight * constraintVec;
|
||||
sumWeight += prevWeight;
|
||||
meanConstraint /= float(sumWeight);
|
||||
|
||||
float residual = 0.0f;
|
||||
float diff = 0.0f;
|
||||
for (int j = 0; j < int(weights.size()); j++)
|
||||
{
|
||||
int w;
|
||||
if (j == int(weights.size() - 1))
|
||||
{
|
||||
cv::vconcat(prevConstraint.rvec(), prevConstraint.translation(), constraintVec);
|
||||
w = prevWeight;
|
||||
}
|
||||
else
|
||||
{
|
||||
Affine3f currObservation = fromSubmapData.constraints[j];
|
||||
cv::vconcat(currObservation.rvec(), currObservation.translation(), constraintVec);
|
||||
w = 1;
|
||||
}
|
||||
|
||||
cv::Vec6f residualVec = (constraintVec - meanConstraint);
|
||||
residual = float(norm(residualVec));
|
||||
float newWeight = huberWeight(residual);
|
||||
diff += w * abs(newWeight - weights[j]);
|
||||
weights[j] = newWeight;
|
||||
}
|
||||
|
||||
if (diff / (prevWeight + weights.size() - 1) < CONVERGE_WEIGHT_THRESHOLD)
|
||||
break;
|
||||
}
|
||||
|
||||
int localInliers = 0;
|
||||
DualQuatf inlierConstraint;
|
||||
for (int i = 0; i < int(weights.size()); i++)
|
||||
{
|
||||
if (weights[i] > INLIER_WEIGHT_THRESH)
|
||||
{
|
||||
localInliers++;
|
||||
if (i == int(weights.size() - 1))
|
||||
inlierConstraint += DualQuatf::createFromMat(prevConstraint.matrix);
|
||||
else
|
||||
inlierConstraint += DualQuatf::createFromMat(fromSubmapData.constraints[i].matrix);
|
||||
}
|
||||
}
|
||||
inlierConstraint = inlierConstraint * 1.0f/float(max(localInliers, 1));
|
||||
inlierPose = inlierConstraint.toAffine3();
|
||||
inliers = localInliers;
|
||||
|
||||
if (inliers >= MIN_INLIERS)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
if(fromSubmapData.trackingAttempts - inliers > (MAX_TRACKING_ATTEMPTS - MIN_INLIERS))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<typename MatType>
|
||||
bool SubmapManager<MatType>::shouldChangeCurrSubmap(int _frameId, int toSubmapId)
|
||||
{
|
||||
auto toSubmap = getSubmap(toSubmapId);
|
||||
auto toSubmapData = activeSubmaps.at(toSubmapId);
|
||||
auto currActiveSubmap = getCurrentSubmap();
|
||||
|
||||
int blocksInNewMap = toSubmap->getTotalAllocatedBlocks();
|
||||
float newRatio = toSubmap->calcVisibilityRatio(_frameId);
|
||||
|
||||
float currRatio = currActiveSubmap->calcVisibilityRatio(_frameId);
|
||||
|
||||
//! TODO: Check for a specific threshold?
|
||||
if (blocksInNewMap <= 0)
|
||||
return false;
|
||||
if ((newRatio > currRatio) && (toSubmapData.type == Type::NEW))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
template<typename MatType>
|
||||
bool SubmapManager<MatType>::addEdgeToCurrentSubmap(const int currentSubmapID, const int tarSubmapID)
|
||||
{
|
||||
Ptr<SubmapT> currentSubmap = getSubmap(currentSubmapID);
|
||||
Ptr<SubmapT> tarSubmap = getSubmap(tarSubmapID);
|
||||
|
||||
return currentSubmap->addEdgeToSubmap(tarSubmapID, tarSubmap->pose);
|
||||
}
|
||||
|
||||
template<typename MatType>
|
||||
bool SubmapManager<MatType>::updateMap(int _frameId, const OdometryFrame& _frame)
|
||||
{
|
||||
bool mapUpdated = false;
|
||||
int changedCurrentMapId = -1;
|
||||
|
||||
const int currSubmapId = getCurrentSubmap()->id;
|
||||
|
||||
for (auto& it : activeSubmaps)
|
||||
{
|
||||
int submapId = it.first;
|
||||
auto& submapData = it.second;
|
||||
if (submapData.type == Type::NEW || submapData.type == Type::LOOP_CLOSURE)
|
||||
{
|
||||
// Check with previous estimate
|
||||
int inliers;
|
||||
Affine3f inlierPose;
|
||||
int constraintUpdate = estimateConstraint(submapId, currSubmapId, inliers, inlierPose);
|
||||
if (constraintUpdate == 1)
|
||||
{
|
||||
typename SubmapT::PoseConstraint& submapConstraint = getSubmap(submapId)->getConstraint(currSubmapId);
|
||||
submapConstraint.accumulatePose(inlierPose, inliers);
|
||||
submapData.constraints.clear();
|
||||
submapData.trackingAttempts = 0;
|
||||
|
||||
if (shouldChangeCurrSubmap(_frameId, submapId))
|
||||
{
|
||||
changedCurrentMapId = submapId;
|
||||
}
|
||||
mapUpdated = true;
|
||||
}
|
||||
else if(constraintUpdate == -1)
|
||||
{
|
||||
submapData.type = Type::LOST;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<int> createNewConstraintsList;
|
||||
for (auto& it : activeSubmaps)
|
||||
{
|
||||
int submapId = it.first;
|
||||
auto& submapData = it.second;
|
||||
|
||||
if (submapId == changedCurrentMapId)
|
||||
{
|
||||
submapData.type = Type::CURRENT;
|
||||
}
|
||||
if ((submapData.type == Type::CURRENT) && (changedCurrentMapId >= 0) && (submapId != changedCurrentMapId))
|
||||
{
|
||||
submapData.type = Type::LOST;
|
||||
createNewConstraintsList.push_back(submapId);
|
||||
}
|
||||
if ((submapData.type == Type::NEW || submapData.type == Type::LOOP_CLOSURE) && (changedCurrentMapId >= 0))
|
||||
{
|
||||
//! TODO: Add a new type called NEW_LOST?
|
||||
submapData.type = Type::LOST;
|
||||
createNewConstraintsList.push_back(submapId);
|
||||
}
|
||||
}
|
||||
|
||||
for (typename IdToActiveSubmaps::iterator it = activeSubmaps.begin(); it != activeSubmaps.end();)
|
||||
{
|
||||
auto& submapData = it->second;
|
||||
if (submapData.type == Type::LOST)
|
||||
it = activeSubmaps.erase(it);
|
||||
else
|
||||
it++;
|
||||
}
|
||||
|
||||
for (std::vector<int>::const_iterator it = createNewConstraintsList.begin(); it != createNewConstraintsList.end(); ++it)
|
||||
{
|
||||
int dataId = *it;
|
||||
ActiveSubmapData newSubmapData;
|
||||
newSubmapData.trackingAttempts = 0;
|
||||
newSubmapData.type = Type::LOOP_CLOSURE;
|
||||
activeSubmaps[dataId] = newSubmapData;
|
||||
}
|
||||
|
||||
if (shouldCreateSubmap(_frameId))
|
||||
{
|
||||
Ptr<SubmapT> currActiveSubmap = getCurrentSubmap();
|
||||
Affine3f newSubmapPose = currActiveSubmap->pose * currActiveSubmap->cameraPose;
|
||||
int submapId = createNewSubmap(false, _frameId, newSubmapPose);
|
||||
auto newSubmap = getSubmap(submapId);
|
||||
newSubmap->frame = _frame;
|
||||
}
|
||||
|
||||
return mapUpdated;
|
||||
}
|
||||
|
||||
template<typename MatType>
|
||||
Ptr<detail::PoseGraph> SubmapManager<MatType>::MapToPoseGraph()
|
||||
{
|
||||
Ptr<detail::PoseGraph> localPoseGraph = detail::PoseGraph::create();
|
||||
|
||||
for(const auto& currSubmap : submapList)
|
||||
{
|
||||
const typename SubmapT::Constraints& constraintList = currSubmap->constraints;
|
||||
for(const auto& currConstraintPair : constraintList)
|
||||
{
|
||||
// TODO: Handle case with duplicate constraints A -> B and B -> A
|
||||
/* Matx66f informationMatrix = Matx66f::eye() * (currConstraintPair.second.weight/10); */
|
||||
Matx66f informationMatrix = Matx66f::eye();
|
||||
localPoseGraph->addEdge(currSubmap->id, currConstraintPair.first, currConstraintPair.second.estimatedPose, informationMatrix);
|
||||
}
|
||||
}
|
||||
|
||||
for(const auto& currSubmap : submapList)
|
||||
{
|
||||
localPoseGraph->addNode(currSubmap->id, currSubmap->pose, (currSubmap->id == 0));
|
||||
}
|
||||
|
||||
return localPoseGraph;
|
||||
}
|
||||
|
||||
template <typename MatType>
|
||||
void SubmapManager<MatType>::PoseGraphToMap(const Ptr<detail::PoseGraph>& updatedPoseGraph)
|
||||
{
|
||||
for(const auto& currSubmap : submapList)
|
||||
{
|
||||
Affine3d pose = updatedPoseGraph->getNodePose(currSubmap->id);
|
||||
if(!updatedPoseGraph->isNodeFixed(currSubmap->id))
|
||||
currSubmap->pose = pose;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace cv
|
||||
|
||||
#endif // include guard
|
||||
@@ -0,0 +1,65 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html
|
||||
|
||||
#ifndef OPENCV_3D_MST_HPP
|
||||
#define OPENCV_3D_MST_HPP
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace cv
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief Represents an edge in a graph for Minimum Spanning Tree (MST) computation.
|
||||
*
|
||||
* Each edge connects two nodes (source and target) and has an associated weight.
|
||||
*/
|
||||
struct CV_EXPORTS_W_SIMPLE MSTEdge
|
||||
{
|
||||
CV_PROP_RW int source, target;
|
||||
CV_PROP_RW double weight;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Represents the algorithms available for building a Minimum Spanning Tree (MST).
|
||||
*
|
||||
* More algorithms may be added in the future.
|
||||
*/
|
||||
enum MSTAlgorithm
|
||||
{
|
||||
MST_PRIM = 0,
|
||||
MST_KRUSKAL = 1
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Builds a Minimum Spanning Tree (MST) using the specified algorithm (see @ref MSTAlgorithm).
|
||||
*
|
||||
* Supports graphs with negative edge weights. Self-loop edges (edges where source and target are the
|
||||
* same) are ignored. If multiple edges exist between the same pair of nodes, only the one with the
|
||||
* lowest weight is considered. If the graph is disconnected or input is invalid, the function
|
||||
* returns false.
|
||||
*
|
||||
* @note The @p root parameter is ignored for algorithms that do not require a starting node.
|
||||
* @note Additional MST algorithms may be supported in the future via the @p algorithm parameter
|
||||
* (see @ref MSTAlgorithm).
|
||||
*
|
||||
* @param numNodes Number of nodes in the graph (must be greater than 0).
|
||||
* @param inputEdges Input vector of edges representing the graph.
|
||||
* @param[out] resultingEdges Output vector to store the edges of the resulting MST.
|
||||
* @param algorithm Specifies which algorithm to use to compute the MST (see @ref MSTAlgorithm).
|
||||
* @param root Starting node for the MST algorithm (only used for certain algorithms).
|
||||
* @return true if a valid MST was successfully built; false otherwise.
|
||||
* @throws cv::Error (StsBadArg) if an invalid algorithm is specified.
|
||||
*/
|
||||
CV_EXPORTS_W bool buildMST(
|
||||
int numNodes,
|
||||
const std::vector<MSTEdge>& inputEdges,
|
||||
CV_OUT std::vector<MSTEdge>& resultingEdges,
|
||||
MSTAlgorithm algorithm,
|
||||
int root = 0
|
||||
);
|
||||
|
||||
} // namespace cv
|
||||
|
||||
#endif // include guard
|
||||
@@ -0,0 +1,112 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html
|
||||
|
||||
#ifndef OPENCV_3D_ODOMETRY_HPP
|
||||
#define OPENCV_3D_ODOMETRY_HPP
|
||||
|
||||
#include <opencv2/core.hpp>
|
||||
|
||||
#include "odometry_frame.hpp"
|
||||
#include "odometry_settings.hpp"
|
||||
|
||||
namespace cv
|
||||
{
|
||||
|
||||
/** These constants are used to set a type of data which odometry will use
|
||||
* @param DEPTH only depth data
|
||||
* @param RGB only rgb image
|
||||
* @param RGB_DEPTH depth and rgb data simultaneously
|
||||
*/
|
||||
enum class OdometryType
|
||||
{
|
||||
DEPTH = 0,
|
||||
RGB = 1,
|
||||
RGB_DEPTH = 2
|
||||
};
|
||||
|
||||
/** These constants are used to set the speed and accuracy of odometry
|
||||
* @param COMMON accurate but not so fast
|
||||
* @param FAST less accurate but faster
|
||||
*/
|
||||
enum class OdometryAlgoType
|
||||
{
|
||||
COMMON = 0,
|
||||
FAST = 1
|
||||
};
|
||||
|
||||
class CV_EXPORTS_W Odometry
|
||||
{
|
||||
public:
|
||||
CV_WRAP Odometry();
|
||||
CV_WRAP explicit Odometry(OdometryType otype);
|
||||
CV_WRAP Odometry(OdometryType otype, const OdometrySettings& settings, OdometryAlgoType algtype);
|
||||
~Odometry();
|
||||
|
||||
/** Prepare frame for odometry calculation
|
||||
* @param frame odometry prepare this frame as src frame and dst frame simultaneously
|
||||
*/
|
||||
CV_WRAP void prepareFrame(OdometryFrame& frame) const;
|
||||
|
||||
/** Prepare frame for odometry calculation
|
||||
* @param srcFrame frame will be prepared as src frame ("original" image)
|
||||
* @param dstFrame frame will be prepared as dsr frame ("rotated" image)
|
||||
*/
|
||||
CV_WRAP void prepareFrames(OdometryFrame& srcFrame, OdometryFrame& dstFrame) const;
|
||||
|
||||
/** Compute Rigid Transformation between two frames so that Rt * src = dst
|
||||
* Both frames, source and destination, should have been prepared by calling prepareFrame() first
|
||||
*
|
||||
* @param srcFrame src frame ("original" image)
|
||||
* @param dstFrame dst frame ("rotated" image)
|
||||
* @param Rt Rigid transformation, which will be calculated, in form:
|
||||
* { R_11 R_12 R_13 t_1
|
||||
* R_21 R_22 R_23 t_2
|
||||
* R_31 R_32 R_33 t_3
|
||||
* 0 0 0 1 }
|
||||
* @return true on success, false if failed to find the transformation
|
||||
*/
|
||||
CV_WRAP bool compute(const OdometryFrame& srcFrame, const OdometryFrame& dstFrame, OutputArray Rt) const;
|
||||
/**
|
||||
* @brief Compute Rigid Transformation between two frames so that Rt * src = dst
|
||||
*
|
||||
* @param srcDepth source depth ("original" image)
|
||||
* @param dstDepth destination depth ("rotated" image)
|
||||
* @param Rt Rigid transformation, which will be calculated, in form:
|
||||
* { R_11 R_12 R_13 t_1
|
||||
* R_21 R_22 R_23 t_2
|
||||
* R_31 R_32 R_33 t_3
|
||||
* 0 0 0 1 }
|
||||
* @return true on success, false if failed to find the transformation
|
||||
*/
|
||||
CV_WRAP bool compute(InputArray srcDepth, InputArray dstDepth, OutputArray Rt) const;
|
||||
/**
|
||||
* @brief Compute Rigid Transformation between two frames so that Rt * src = dst
|
||||
*
|
||||
* @param srcDepth source depth ("original" image)
|
||||
* @param srcRGB source RGB
|
||||
* @param dstDepth destination depth ("rotated" image)
|
||||
* @param dstRGB destination RGB
|
||||
* @param Rt Rigid transformation, which will be calculated, in form:
|
||||
* { R_11 R_12 R_13 t_1
|
||||
* R_21 R_22 R_23 t_2
|
||||
* R_31 R_32 R_33 t_3
|
||||
* 0 0 0 1 }
|
||||
* @return true on success, false if failed to find the transformation
|
||||
*/
|
||||
CV_WRAP bool compute(InputArray srcDepth, InputArray srcRGB, InputArray dstDepth, InputArray dstRGB, OutputArray Rt) const;
|
||||
|
||||
/**
|
||||
* @brief Get the normals computer object used for normals calculation (if presented).
|
||||
* The normals computer is generated at first need during prepareFrame when normals are required for the ICP algorithm
|
||||
* but not presented by a user. Re-generated each time the related settings change or a new frame arrives with the different size.
|
||||
*/
|
||||
CV_WRAP Ptr<RgbdNormals> getNormalsComputer() const;
|
||||
|
||||
class Impl;
|
||||
private:
|
||||
Ptr<Impl> impl;
|
||||
};
|
||||
|
||||
}
|
||||
#endif //OPENCV_3D_ODOMETRY_HPP
|
||||
@@ -0,0 +1,108 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html
|
||||
|
||||
#ifndef OPENCV_3D_ODOMETRY_FRAME_HPP
|
||||
#define OPENCV_3D_ODOMETRY_FRAME_HPP
|
||||
|
||||
#include <opencv2/core.hpp>
|
||||
|
||||
namespace cv
|
||||
{
|
||||
/** Indicates what pyramid is to access using getPyramidAt() method:
|
||||
*/
|
||||
|
||||
enum OdometryFramePyramidType
|
||||
{
|
||||
PYR_IMAGE = 0, //!< The pyramid of grayscale images
|
||||
PYR_DEPTH = 1, //!< The pyramid of depth images
|
||||
PYR_MASK = 2, //!< The pyramid of masks
|
||||
PYR_CLOUD = 3, //!< The pyramid of point clouds, produced from the pyramid of depths
|
||||
PYR_DIX = 4, //!< The pyramid of dI/dx derivative images
|
||||
PYR_DIY = 5, //!< The pyramid of dI/dy derivative images
|
||||
PYR_TEXMASK = 6, //!< The pyramid of "textured" masks (i.e. additional masks for normals or grayscale images)
|
||||
PYR_NORM = 7, //!< The pyramid of normals
|
||||
PYR_NORMMASK = 8, //!< The pyramid of normals masks
|
||||
N_PYRAMIDS
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief An object that keeps per-frame data for Odometry algorithms from user-provided images to algorithm-specific precalculated data.
|
||||
* When not empty, it contains a depth image, a mask of valid pixels and a set of pyramids generated from that data.
|
||||
* A BGR/Gray image and normals are optional.
|
||||
* OdometryFrame is made to be used together with Odometry class to reuse precalculated data between Rt data calculations.
|
||||
* A correct way to do that is to call Odometry::prepareFrames() on prev and next frames and then pass them to Odometry::compute() method.
|
||||
*/
|
||||
class CV_EXPORTS_W_SIMPLE OdometryFrame
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Construct a new OdometryFrame object. All non-empty images should have the same size.
|
||||
*
|
||||
* @param depth A depth image, should be CV_8UC1
|
||||
* @param image An BGR or grayscale image (or noArray() if it's not required for used ICP algorithm).
|
||||
* Should be CV_8UC3 or CV_8C4 if it's BGR image or CV_8UC1 if it's grayscale. If it's BGR then it's converted to grayscale
|
||||
* image automatically.
|
||||
* @param mask A user-provided mask of valid pixels, should be CV_8UC1
|
||||
* @param normals A user-provided normals to the depth surface, should be CV_32FC4
|
||||
*/
|
||||
CV_WRAP explicit OdometryFrame(InputArray depth = noArray(), InputArray image = noArray(), InputArray mask = noArray(), InputArray normals = noArray());
|
||||
~OdometryFrame() {};
|
||||
|
||||
/**
|
||||
* @brief Get the original user-provided BGR/Gray image
|
||||
*
|
||||
* @param image Output image
|
||||
*/
|
||||
CV_WRAP void getImage(OutputArray image) const;
|
||||
/**
|
||||
* @brief Get the gray image generated from the user-provided BGR/Gray image
|
||||
*
|
||||
* @param image Output image
|
||||
*/
|
||||
CV_WRAP void getGrayImage(OutputArray image) const;
|
||||
/**
|
||||
* @brief Get the original user-provided depth image
|
||||
*
|
||||
* @param depth Output image
|
||||
*/
|
||||
CV_WRAP void getDepth(OutputArray depth) const;
|
||||
/**
|
||||
* @brief Get the depth image generated from the user-provided one after conversion, rescale or filtering for ICP algorithm needs
|
||||
*
|
||||
* @param depth Output image
|
||||
*/
|
||||
CV_WRAP void getProcessedDepth(OutputArray depth) const;
|
||||
/**
|
||||
* @brief Get the valid pixels mask generated for the ICP calculations intersected with the user-provided mask
|
||||
*
|
||||
* @param mask Output image
|
||||
*/
|
||||
CV_WRAP void getMask(OutputArray mask) const;
|
||||
/**
|
||||
* @brief Get the normals image either generated for the ICP calculations or user-provided
|
||||
*
|
||||
* @param normals Output image
|
||||
*/
|
||||
CV_WRAP void getNormals(OutputArray normals) const;
|
||||
|
||||
/**
|
||||
* @brief Get the amount of levels in pyramids (all of them if not empty should have the same number of levels)
|
||||
* or 0 if no pyramids were prepared yet
|
||||
*/
|
||||
CV_WRAP int getPyramidLevels() const;
|
||||
/**
|
||||
* @brief Get the image generated for the ICP calculations from one of the pyramids specified by pyrType. Returns empty image if
|
||||
* the pyramid is empty or there's no such pyramid level
|
||||
*
|
||||
* @param img Output image
|
||||
* @param pyrType Type of pyramid
|
||||
* @param level Level in the pyramid
|
||||
*/
|
||||
CV_WRAP void getPyramidAt(OutputArray img, OdometryFramePyramidType pyrType, size_t level) const;
|
||||
|
||||
class Impl;
|
||||
Ptr<Impl> impl;
|
||||
};
|
||||
}
|
||||
#endif // !OPENCV_3D_ODOMETRY_FRAME_HPP
|
||||
@@ -0,0 +1,65 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html
|
||||
|
||||
#ifndef OPENCV_3D_ODOMETRY_SETTINGS_HPP
|
||||
#define OPENCV_3D_ODOMETRY_SETTINGS_HPP
|
||||
|
||||
#include <opencv2/core.hpp>
|
||||
|
||||
namespace cv
|
||||
{
|
||||
|
||||
class CV_EXPORTS_W_SIMPLE OdometrySettings
|
||||
{
|
||||
public:
|
||||
CV_WRAP OdometrySettings();
|
||||
OdometrySettings(const OdometrySettings&);
|
||||
OdometrySettings& operator=(const OdometrySettings&);
|
||||
~OdometrySettings() {};
|
||||
CV_WRAP void setCameraMatrix(InputArray val);
|
||||
CV_WRAP void getCameraMatrix(OutputArray val) const;
|
||||
CV_WRAP void setIterCounts(InputArray val);
|
||||
CV_WRAP void getIterCounts(OutputArray val) const;
|
||||
|
||||
CV_WRAP void setMinDepth(float val);
|
||||
CV_WRAP float getMinDepth() const;
|
||||
CV_WRAP void setMaxDepth(float val);
|
||||
CV_WRAP float getMaxDepth() const;
|
||||
CV_WRAP void setMaxDepthDiff(float val);
|
||||
CV_WRAP float getMaxDepthDiff() const;
|
||||
CV_WRAP void setMaxPointsPart(float val);
|
||||
CV_WRAP float getMaxPointsPart() const;
|
||||
|
||||
CV_WRAP void setSobelSize(int val);
|
||||
CV_WRAP int getSobelSize() const;
|
||||
CV_WRAP void setSobelScale(double val);
|
||||
CV_WRAP double getSobelScale() const;
|
||||
|
||||
CV_WRAP void setNormalWinSize(int val);
|
||||
CV_WRAP int getNormalWinSize() const;
|
||||
CV_WRAP void setNormalDiffThreshold(float val);
|
||||
CV_WRAP float getNormalDiffThreshold() const;
|
||||
CV_WRAP void setNormalMethod(RgbdNormals::RgbdNormalsMethod nm);
|
||||
CV_WRAP RgbdNormals::RgbdNormalsMethod getNormalMethod() const;
|
||||
|
||||
CV_WRAP void setAngleThreshold(float val);
|
||||
CV_WRAP float getAngleThreshold() const;
|
||||
CV_WRAP void setMaxTranslation(float val);
|
||||
CV_WRAP float getMaxTranslation() const;
|
||||
CV_WRAP void setMaxRotation(float val);
|
||||
CV_WRAP float getMaxRotation() const;
|
||||
|
||||
CV_WRAP void setMinGradientMagnitude(float val);
|
||||
CV_WRAP float getMinGradientMagnitude() const;
|
||||
CV_WRAP void setMinGradientMagnitudes(InputArray val);
|
||||
CV_WRAP void getMinGradientMagnitudes(OutputArray val) const;
|
||||
|
||||
class Impl;
|
||||
|
||||
private:
|
||||
Ptr<Impl> impl;
|
||||
};
|
||||
|
||||
}
|
||||
#endif //OPENCV_3D_ODOMETRY_SETTINGS_HPP
|
||||
@@ -0,0 +1,411 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
//
|
||||
// Copyright (C) 2021, Yechun Ruan <ruanyc@mail.sustech.edu.cn>
|
||||
|
||||
|
||||
#ifndef OPENCV_3D_PTCLOUD_HPP
|
||||
#define OPENCV_3D_PTCLOUD_HPP
|
||||
|
||||
namespace cv {
|
||||
|
||||
//! @addtogroup _3d
|
||||
//! @{
|
||||
|
||||
|
||||
//! type of the robust estimation algorithm
|
||||
enum SacMethod
|
||||
{
|
||||
/** The RANSAC algorithm described in @cite fischler1981random.
|
||||
*/
|
||||
SAC_METHOD_RANSAC,
|
||||
// SAC_METHOD_MAGSAC,
|
||||
// SAC_METHOD_LMEDS,
|
||||
// SAC_METHOD_MSAC,
|
||||
// SAC_METHOD_RRANSAC,
|
||||
// SAC_METHOD_RMSAC,
|
||||
// SAC_METHOD_MLESAC,
|
||||
// SAC_METHOD_PROSAC
|
||||
};
|
||||
|
||||
enum SacModelType
|
||||
{
|
||||
/** The 3D PLANE model coefficients in list **[a, b, c, d]**,
|
||||
corresponding to the coefficients of equation
|
||||
\f$ ax + by + cz + d = 0 \f$. */
|
||||
SAC_MODEL_PLANE,
|
||||
/** The 3D SPHERE model coefficients in list **[center_x, center_y, center_z, radius]**,
|
||||
corresponding to the coefficients of equation
|
||||
\f$ (x - center\_x)^2 + (y - center\_y)^2 + (z - center\_z)^2 = radius^2 \f$.*/
|
||||
SAC_MODEL_SPHERE,
|
||||
// SAC_MODEL_CYLINDER,
|
||||
|
||||
};
|
||||
|
||||
|
||||
/** @brief Sample Consensus algorithm segmentation of 3D point cloud model.
|
||||
|
||||
Example of segmenting plane from a 3D point cloud using the RANSAC algorithm:
|
||||
@snippet snippets/3d_sac_segmentation.cpp planeSegmentationUsingRANSAC
|
||||
|
||||
@see
|
||||
1. Supported algorithms: enum SacMethod in ptcloud.hpp.
|
||||
2. Supported models: enum SacModelType in ptcloud.hpp.
|
||||
*/
|
||||
class CV_EXPORTS SACSegmentation
|
||||
{
|
||||
public:
|
||||
/** @brief Custom function that take the model coefficients and return whether the model is acceptable or not.
|
||||
|
||||
Example of constructing SACSegmentation::ModelConstraintFunction:
|
||||
@snippet snippets/3d_sac_segmentation.cpp usageExampleSacModelConstraintFunction
|
||||
|
||||
@note The content of model_coefficients depends on the model.
|
||||
Refer to the comments inside enumeration type SacModelType.
|
||||
*/
|
||||
using ModelConstraintFunction =
|
||||
std::function<bool(const std::vector<double> &/*model_coefficients*/)>;
|
||||
|
||||
//-------------------------- CREATE -----------------------
|
||||
|
||||
static Ptr<SACSegmentation> create(SacModelType sac_model_type = SAC_MODEL_PLANE,
|
||||
SacMethod sac_method = SAC_METHOD_RANSAC,
|
||||
double threshold = 0.5, int max_iterations = 1000);
|
||||
|
||||
// -------------------------- CONSTRUCTOR, DESTRUCTOR --------------------------
|
||||
|
||||
SACSegmentation() = default;
|
||||
|
||||
virtual ~SACSegmentation() = default;
|
||||
|
||||
//-------------------------- SEGMENT -----------------------
|
||||
|
||||
/**
|
||||
* @brief Execute segmentation using the sample consensus method.
|
||||
*
|
||||
* @param input_pts Original point cloud, vector of Point3 or Mat of size Nx3/3xN.
|
||||
* @param[out] labels The label corresponds to the model number, 0 means it
|
||||
* does not belong to any model, range [0, Number of final resultant models obtained].
|
||||
* @param[out] models_coefficients The resultant models coefficients.
|
||||
* Currently supports passing in cv::Mat. Models coefficients are placed in a matrix of NxK
|
||||
* with depth CV_64F (will automatically adjust if the passing one does not look like this),
|
||||
* where N is the number of models and K is the number of coefficients of one model.
|
||||
* The coefficients for each model refer to the comments inside enumeration type SacModelType.
|
||||
* @return Number of final resultant models obtained by segmentation.
|
||||
*/
|
||||
virtual int
|
||||
segment(InputArray input_pts, OutputArray labels, OutputArray models_coefficients) = 0;
|
||||
|
||||
//-------------------------- Getter and Setter -----------------------
|
||||
|
||||
//! Set the type of sample consensus model to use.
|
||||
virtual void setSacModelType(SacModelType sac_model_type) = 0;
|
||||
|
||||
//! Get the type of sample consensus model used.
|
||||
virtual SacModelType getSacModelType() const = 0;
|
||||
|
||||
//! Set the type of sample consensus method to use.
|
||||
virtual void setSacMethodType(SacMethod sac_method) = 0;
|
||||
|
||||
//! Get the type of sample consensus method used.
|
||||
virtual SacMethod getSacMethodType() const = 0;
|
||||
|
||||
//! Set the distance to the model threshold.
|
||||
//! Considered as inlier point if distance to the model less than threshold.
|
||||
virtual void setDistanceThreshold(double threshold) = 0;
|
||||
|
||||
//! Get the distance to the model threshold.
|
||||
virtual double getDistanceThreshold() const = 0;
|
||||
|
||||
//! Set the minimum and maximum radius limits for the model.
|
||||
//! Only used for models whose model parameters include a radius.
|
||||
virtual void setRadiusLimits(double radius_min, double radius_max) = 0;
|
||||
|
||||
//! Get the minimum and maximum radius limits for the model.
|
||||
virtual void getRadiusLimits(double &radius_min, double &radius_max) const = 0;
|
||||
|
||||
//! Set the maximum number of iterations to attempt.
|
||||
virtual void setMaxIterations(int max_iterations) = 0;
|
||||
|
||||
//! Get the maximum number of iterations to attempt.
|
||||
virtual int getMaxIterations() const = 0;
|
||||
|
||||
//! Set the confidence that ensure at least one of selections is an error-free set of data points.
|
||||
virtual void setConfidence(double confidence) = 0;
|
||||
|
||||
//! Get the confidence that ensure at least one of selections is an error-free set of data points.
|
||||
virtual double getConfidence() const = 0;
|
||||
|
||||
//! Set the number of models expected.
|
||||
virtual void setNumberOfModelsExpected(int number_of_models_expected) = 0;
|
||||
|
||||
//! Get the expected number of models.
|
||||
virtual int getNumberOfModelsExpected() const = 0;
|
||||
|
||||
//! Set whether to use parallelism or not.
|
||||
//! The number of threads is set by cv::setNumThreads(int nthreads).
|
||||
virtual void setParallel(bool is_parallel) = 0;
|
||||
|
||||
//! Get whether to use parallelism or not.
|
||||
virtual bool isParallel() const = 0;
|
||||
|
||||
//! Set state used to initialize the RNG(Random Number Generator).
|
||||
virtual void setRandomGeneratorState(uint64 rng_state) = 0;
|
||||
|
||||
//! Get state used to initialize the RNG(Random Number Generator).
|
||||
virtual uint64 getRandomGeneratorState() const = 0;
|
||||
|
||||
//! Set custom model coefficient constraint function.
|
||||
//! A custom function that takes model coefficients and returns whether the model is acceptable or not.
|
||||
virtual void
|
||||
setCustomModelConstraints(const ModelConstraintFunction &custom_model_constraints) = 0;
|
||||
|
||||
//! Get custom model coefficient constraint function.
|
||||
virtual const ModelConstraintFunction &getCustomModelConstraints() const = 0;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Point cloud sampling by Voxel Grid filter downsampling.
|
||||
*
|
||||
* Creates a 3D voxel grid (a set of tiny 3D boxes in space) over the input
|
||||
* point cloud data, in each voxel (i.e., 3D box), all the points present will be
|
||||
* approximated (i.e., downsampled) with the point closest to their centroid.
|
||||
*
|
||||
* @param[out] sampled_point_flags Flags of the sampled point, (pass in std::vector<int> or std::vector<char> etc.)
|
||||
* sampled_point_flags[i] is 1 means i-th point selected, 0 means it is not selected.
|
||||
* @param input_pts Original point cloud, vector of Point3 or Mat of size Nx3/3xN.
|
||||
* @param length Grid length.
|
||||
* @param width Grid width.
|
||||
* @param height Grid height.
|
||||
* @return The number of points actually sampled.
|
||||
*/
|
||||
CV_EXPORTS int voxelGridSampling(OutputArray sampled_point_flags, InputArray input_pts,
|
||||
float length, float width, float height);
|
||||
|
||||
/**
|
||||
* @brief Point cloud sampling by randomly select points.
|
||||
*
|
||||
* Use cv::randShuffle to shuffle the point index list,
|
||||
* then take the points corresponding to the front part of the list.
|
||||
*
|
||||
* @param sampled_pts Point cloud after sampling.
|
||||
* Support cv::Mat(sampled_pts_size, 3, CV_32F), std::vector<cv::Point3f>.
|
||||
* @param input_pts Original point cloud, vector of Point3 or Mat of size Nx3/3xN.
|
||||
* @param sampled_pts_size The desired point cloud size after sampling.
|
||||
* @param rng Optional random number generator used for cv::randShuffle;
|
||||
* if it is nullptr, theRNG () is used instead.
|
||||
*/
|
||||
CV_EXPORTS void randomSampling(OutputArray sampled_pts, InputArray input_pts,
|
||||
int sampled_pts_size, RNG *rng = nullptr);
|
||||
|
||||
/**
|
||||
* @overload
|
||||
*
|
||||
* @param sampled_pts Point cloud after sampling.
|
||||
* Support cv::Mat(size * sampled_scale, 3, CV_32F), std::vector<cv::Point3f>.
|
||||
* @param input_pts Original point cloud, vector of Point3 or Mat of size Nx3/3xN.
|
||||
* @param sampled_scale Range (0, 1), the percentage of the sampled point cloud to the original size,
|
||||
* that is, sampled size = original size * sampled_scale.
|
||||
* @param rng Optional random number generator used for cv::randShuffle;
|
||||
* if it is nullptr, theRNG () is used instead.
|
||||
*/
|
||||
CV_EXPORTS void randomSampling(OutputArray sampled_pts, InputArray input_pts,
|
||||
float sampled_scale, RNG *rng = nullptr);
|
||||
|
||||
/**
|
||||
* @brief Point cloud sampling by Farthest Point Sampling(FPS).
|
||||
*
|
||||
* FPS Algorithm:
|
||||
* + Input: Point cloud *C*, *sampled_pts_size*, *dist_lower_limit*
|
||||
* + Initialize: Set sampled point cloud S to the empty set
|
||||
* + Step:
|
||||
* 1. Randomly take a seed point from C and take it from C to S;
|
||||
* 2. Find a point in C that is the farthest away from S and take it from C to S;
|
||||
* (The distance from point to set S is the smallest distance from point to all points in S)
|
||||
* 3. Repeat *step 2* until the farthest distance of the point in C from S
|
||||
* is less than *dist_lower_limit*, or the size of S is equal to *sampled_pts_size*.
|
||||
* + Output: Sampled point cloud S
|
||||
*
|
||||
* @param[out] sampled_point_flags Flags of the sampled point, (pass in std::vector<int> or std::vector<char> etc.)
|
||||
* sampled_point_flags[i] is 1 means i-th point selected, 0 means it is not selected.
|
||||
* @param input_pts Original point cloud, vector of Point3 or Mat of size Nx3/3xN.
|
||||
* @param sampled_pts_size The desired point cloud size after sampling.
|
||||
* @param dist_lower_limit Sampling is terminated early if the distance from
|
||||
* the farthest point to S is less than dist_lower_limit, default 0.
|
||||
* @param rng Optional random number generator used for selecting seed point for FPS;
|
||||
* if it is nullptr, theRNG () is used instead.
|
||||
* @return The number of points actually sampled.
|
||||
*/
|
||||
CV_EXPORTS int farthestPointSampling(OutputArray sampled_point_flags, InputArray input_pts,
|
||||
int sampled_pts_size, float dist_lower_limit = 0, RNG *rng = nullptr);
|
||||
|
||||
/**
|
||||
* @overload
|
||||
*
|
||||
* @param[out] sampled_point_flags Flags of the sampled point, (pass in std::vector<int> or std::vector<char> etc.)
|
||||
* sampled_point_flags[i] is 1 means i-th point selected, 0 means it is not selected.
|
||||
* @param input_pts Original point cloud, vector of Point3 or Mat of size Nx3/3xN.
|
||||
* @param sampled_scale Range (0, 1), the percentage of the sampled point cloud to the original size,
|
||||
* that is, sampled size = original size * sampled_scale.
|
||||
* @param dist_lower_limit Sampling is terminated early if the distance from
|
||||
* the farthest point to S is less than dist_lower_limit, default 0.
|
||||
* @param rng Optional random number generator used for selecting seed point for FPS;
|
||||
* if it is nullptr, theRNG () is used instead.
|
||||
* @return The number of points actually sampled.
|
||||
*/
|
||||
CV_EXPORTS int farthestPointSampling(OutputArray sampled_point_flags, InputArray input_pts,
|
||||
float sampled_scale, float dist_lower_limit = 0, RNG *rng = nullptr);
|
||||
|
||||
/**
|
||||
* @brief Estimate the normal and curvature of each point in point cloud from NN results.
|
||||
*
|
||||
* Normal estimation by PCA:
|
||||
* + Input: Nearest neighbor points of a specific point: \f$ pt\_set \f$
|
||||
* + Step:
|
||||
* 1. Calculate the \f$ mean(\bar{x},\bar{y},\bar{z}) \f$ of \f$ pt\_set \f$;
|
||||
* 2. A 3x3 covariance matrix \f$ cov \f$ is obtained by \f$ mean^T \cdot mean \f$;
|
||||
* 3. Calculate the eigenvalues(\f$ λ_2 \ge λ_1 \ge λ_0 \f$) and corresponding
|
||||
* eigenvectors(\f$ v_2, v_1, v_0 \f$) of \f$ cov \f$;
|
||||
* 4. \f$ v0 \f$ is the normal of the specific point,
|
||||
* \f$ \frac{λ_0}{λ_0 + λ_1 + λ_2} \f$ is the curvature of the specific point;
|
||||
* + Output: Normal and curvature of the specific point.
|
||||
*
|
||||
* @param[out] normals Normal of each point, support vector<Point3f> and Mat of size Nx3.
|
||||
* @param[out] curvatures Curvature of each point, support vector<float> and Mat.
|
||||
* @param input_pts Original point cloud, support vector<Point3f> and Mat of size Nx3/3xN.
|
||||
* @param nn_idx Index information of nearest neighbors of all points. The first nearest neighbor of
|
||||
* each point is itself. Support vector<vector<int>>, vector<Mat> and Mat of size NxK.
|
||||
* If the information in a row is [0, 2, 1, -5, -1, 4, 7 ... negative number], it will
|
||||
* use only non-negative indexes until it meets a negative number or bound of this row
|
||||
* i.e. [0, 2, 1].
|
||||
* @param max_neighbor_num The maximum number of neighbors want to use including itself. Setting to
|
||||
* a non-positive number or default will use the information from nn_idx.
|
||||
*/
|
||||
|
||||
CV_EXPORTS void normalEstimate(OutputArray normals, OutputArray curvatures, InputArray input_pts,
|
||||
InputArrayOfArrays nn_idx, int max_neighbor_num = 0);
|
||||
|
||||
/**
|
||||
* @brief Region Growing algorithm in 3D point cloud.
|
||||
*
|
||||
* The key idea of region growing is to merge the nearest neighbor points that satisfy a certain
|
||||
* angle threshold into the same region according to the normal between the two points, so as to
|
||||
* achieve the purpose of segmentation. For more details, please refer to @cite Rabbani2006SegmentationOP.
|
||||
*/
|
||||
class CV_EXPORTS RegionGrowing3D
|
||||
{
|
||||
public:
|
||||
//-------------------------- CREATE -----------------------
|
||||
|
||||
static Ptr<RegionGrowing3D> create();
|
||||
|
||||
// -------------------------- CONSTRUCTOR, DESTRUCTOR --------------------------
|
||||
|
||||
RegionGrowing3D() = default;
|
||||
|
||||
virtual ~RegionGrowing3D() = default;
|
||||
|
||||
//-------------------------- SEGMENT -----------------------
|
||||
|
||||
/**
|
||||
* @brief Execute segmentation using the Region Growing algorithm.
|
||||
*
|
||||
* @param[out] regions_idx Index information of all points in each region, support
|
||||
* vector<vector<int>>, vector<Mat>.
|
||||
* @param[out] labels The label corresponds to the model number, 0 means it does not belong to
|
||||
* any model, range [0, Number of final resultant models obtained]. Support
|
||||
* vector<int> and Mat.
|
||||
* @param input_pts Original point cloud, support vector<Point3f> and Mat of size Nx3/3xN.
|
||||
* @param normals Normal of each point, support vector<Point3f> and Mat of size Nx3.
|
||||
* @param nn_idx Index information of nearest neighbors of all points. The first nearest
|
||||
* neighbor of each point is itself. Support vector<vector<int>>, vector<Mat> and
|
||||
* Mat of size NxK. If the information in a row is
|
||||
* [0, 2, 1, -5, -1, 4, 7 ... negative number]
|
||||
* it will use only non-negative indexes until it meets a negative number or bound
|
||||
* of this row i.e. [0, 2, 1].
|
||||
* @return Number of final resultant regions obtained by segmentation.
|
||||
*/
|
||||
virtual int
|
||||
segment(OutputArrayOfArrays regions_idx, OutputArray labels, InputArray input_pts,
|
||||
InputArray normals, InputArrayOfArrays nn_idx) = 0;
|
||||
|
||||
//-------------------------- Getter and Setter -----------------------
|
||||
|
||||
//! Set the minimum size of region.
|
||||
//!Setting to a non-positive number or default will be unlimited.
|
||||
virtual void setMinSize(int min_size) = 0;
|
||||
|
||||
//! Get the minimum size of region.
|
||||
virtual int getMinSize() const = 0;
|
||||
|
||||
//! Set the maximum size of region.
|
||||
//!Setting to a non-positive number or default will be unlimited.
|
||||
virtual void setMaxSize(int max_size) = 0;
|
||||
|
||||
//! Get the maximum size of region.
|
||||
virtual int getMaxSize() const = 0;
|
||||
|
||||
//! Set whether to use the smoothness mode. Default will be true.
|
||||
//! If true it will check the angle between the normal of the current point and the normal of its neighbor.
|
||||
//! Otherwise, it will check the angle between the normal of the seed point and the normal of current neighbor.
|
||||
virtual void setSmoothModeFlag(bool smooth_mode) = 0;
|
||||
|
||||
//! Get whether to use the smoothness mode.
|
||||
virtual bool getSmoothModeFlag() const = 0;
|
||||
|
||||
//! Set threshold value of the angle between normals, the input value is in radian.
|
||||
//!Default will be 30(degree)*PI/180.
|
||||
virtual void setSmoothnessThreshold(double smoothness_thr) = 0;
|
||||
|
||||
//! Get threshold value of the angle between normals.
|
||||
virtual double getSmoothnessThreshold() const = 0;
|
||||
|
||||
//! Set threshold value of curvature. Default will be 0.05.
|
||||
//! Only points with curvature less than the threshold will be considered to belong to the same region.
|
||||
//! If the curvature of each point is not set, this option will not work.
|
||||
virtual void setCurvatureThreshold(double curvature_thr) = 0;
|
||||
|
||||
//! Get threshold value of curvature.
|
||||
virtual double getCurvatureThreshold() const = 0;
|
||||
|
||||
//! Set the maximum number of neighbors want to use including itself.
|
||||
//! Setting to a non-positive number or default will use the information from nn_idx.
|
||||
virtual void setMaxNumberOfNeighbors(int max_neighbor_num) = 0;
|
||||
|
||||
//! Get the maximum number of neighbors including itself.
|
||||
virtual int getMaxNumberOfNeighbors() const = 0;
|
||||
|
||||
//! Set the maximum number of regions you want.
|
||||
//!Setting to a non-positive number or default will be unlimited.
|
||||
virtual void setNumberOfRegions(int region_num) = 0;
|
||||
|
||||
//! Get the maximum number of regions you want.
|
||||
virtual int getNumberOfRegions() const = 0;
|
||||
|
||||
//! Set whether the results need to be sorted in descending order by the number of points.
|
||||
virtual void setNeedSort(bool need_sort) = 0;
|
||||
|
||||
//! Get whether the results need to be sorted you have set.
|
||||
virtual bool getNeedSort() const = 0;
|
||||
|
||||
//! Set the seed points, it will grow according to the seeds.
|
||||
//! If noArray() is set, the default method will be used:
|
||||
//! 1. If the curvature of each point is set, the seeds will be sorted in ascending order of curvatures.
|
||||
//! 2. Otherwise, the natural order of the point cloud will be used.
|
||||
virtual void setSeeds(InputArray seeds) = 0;
|
||||
|
||||
//! Get the seed points.
|
||||
virtual void getSeeds(OutputArray seeds) const = 0;
|
||||
|
||||
//! Set the curvature of each point, support vector<float> and Mat. If not, you can set it to noArray().
|
||||
virtual void setCurvatures(InputArray curvatures) = 0;
|
||||
|
||||
//! Get the curvature of each point if you have set.
|
||||
virtual void getCurvatures(OutputArray curvatures) const = 0;
|
||||
};
|
||||
//! @} _3d
|
||||
} //end namespace cv
|
||||
#endif //OPENCV_3D_PTCLOUD_HPP
|
||||
@@ -0,0 +1,171 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html
|
||||
|
||||
#ifndef OPENCV_3D_VOLUME_HPP
|
||||
#define OPENCV_3D_VOLUME_HPP
|
||||
|
||||
#include "volume_settings.hpp"
|
||||
|
||||
#include "opencv2/core/affine.hpp"
|
||||
|
||||
namespace cv
|
||||
{
|
||||
|
||||
class CV_EXPORTS_W Volume
|
||||
{
|
||||
public:
|
||||
/** @brief Constructor of custom volume.
|
||||
* @param vtype the volume type [TSDF, HashTSDF, ColorTSDF].
|
||||
* @param settings the custom settings for volume.
|
||||
*/
|
||||
CV_WRAP explicit Volume(VolumeType vtype = VolumeType::TSDF,
|
||||
const VolumeSettings& settings = VolumeSettings(VolumeType::TSDF));
|
||||
~Volume();
|
||||
|
||||
/** @brief Integrates the input data to the volume.
|
||||
|
||||
Camera intrinsics are taken from volume settings structure.
|
||||
|
||||
* @param frame the object from which to take depth and image data.
|
||||
For color TSDF a depth data should be registered with color data, i.e. have the same intrinsics & camera pose.
|
||||
This can be done using function registerDepth() from 3d module.
|
||||
* @param pose the pose of camera in global coordinates.
|
||||
*/
|
||||
CV_WRAP_AS(integrateFrame) void integrate(const OdometryFrame& frame, InputArray pose);
|
||||
|
||||
/** @brief Integrates the input data to the volume.
|
||||
|
||||
Camera intrinsics are taken from volume settings structure.
|
||||
|
||||
* @param depth the depth image.
|
||||
* @param pose the pose of camera in global coordinates.
|
||||
*/
|
||||
CV_WRAP_AS(integrate) void integrate(InputArray depth, InputArray pose);
|
||||
|
||||
/** @brief Integrates the input data to the volume.
|
||||
|
||||
Camera intrinsics are taken from volume settings structure.
|
||||
|
||||
* @param depth the depth image.
|
||||
* @param image the color image (only for ColorTSDF).
|
||||
For color TSDF a depth data should be registered with color data, i.e. have the same intrinsics & camera pose.
|
||||
This can be done using function registerDepth() from 3d module.
|
||||
* @param pose the pose of camera in global coordinates.
|
||||
*/
|
||||
CV_WRAP_AS(integrateColor) void integrate(InputArray depth, InputArray image, InputArray pose);
|
||||
|
||||
// Python bindings do not process noArray() default argument correctly, so the raycast() method is repeated several times
|
||||
|
||||
/** @brief Renders the volume contents into an image. The resulting points and normals are in camera's coordinate system.
|
||||
|
||||
Rendered image size and camera intrinsics are taken from volume settings structure.
|
||||
|
||||
* @param cameraPose the pose of camera in global coordinates.
|
||||
* @param points image to store rendered points.
|
||||
* @param normals image to store rendered normals corresponding to points.
|
||||
*/
|
||||
CV_WRAP void raycast(InputArray cameraPose, OutputArray points, OutputArray normals) const;
|
||||
|
||||
/** @brief Renders the volume contents into an image. The resulting points and normals are in camera's coordinate system.
|
||||
|
||||
Rendered image size and camera intrinsics are taken from volume settings structure.
|
||||
|
||||
* @param cameraPose the pose of camera in global coordinates.
|
||||
* @param points image to store rendered points.
|
||||
* @param normals image to store rendered normals corresponding to points.
|
||||
* @param colors image to store rendered colors corresponding to points (only for ColorTSDF).
|
||||
*/
|
||||
CV_WRAP_AS(raycastColor) void raycast(InputArray cameraPose, OutputArray points, OutputArray normals, OutputArray colors) const;
|
||||
|
||||
/** @brief Renders the volume contents into an image. The resulting points and normals are in camera's coordinate system.
|
||||
|
||||
Rendered image size and camera intrinsics are taken from volume settings structure.
|
||||
|
||||
* @param cameraPose the pose of camera in global coordinates.
|
||||
* @param height the height of result image
|
||||
* @param width the width of result image
|
||||
* @param K camera raycast intrinsics
|
||||
* @param points image to store rendered points.
|
||||
* @param normals image to store rendered normals corresponding to points.
|
||||
*/
|
||||
CV_WRAP_AS(raycastEx) void raycast(InputArray cameraPose, int height, int width, InputArray K, OutputArray points, OutputArray normals) const;
|
||||
|
||||
|
||||
/** @brief Renders the volume contents into an image. The resulting points and normals are in camera's coordinate system.
|
||||
|
||||
Rendered image size and camera intrinsics are taken from volume settings structure.
|
||||
|
||||
* @param cameraPose the pose of camera in global coordinates.
|
||||
* @param height the height of result image
|
||||
* @param width the width of result image
|
||||
* @param K camera raycast intrinsics
|
||||
* @param points image to store rendered points.
|
||||
* @param normals image to store rendered normals corresponding to points.
|
||||
* @param colors image to store rendered colors corresponding to points (only for ColorTSDF).
|
||||
*/
|
||||
CV_WRAP_AS(raycastExColor) void raycast(InputArray cameraPose, int height, int width, InputArray K, OutputArray points, OutputArray normals, OutputArray colors) const;
|
||||
|
||||
/** @brief Extract the all data from volume.
|
||||
* @param points the input exist point.
|
||||
* @param normals the storage of normals (corresponding to input points) in the image.
|
||||
*/
|
||||
CV_WRAP void fetchNormals(InputArray points, OutputArray normals) const;
|
||||
/** @brief Extract the all data from volume.
|
||||
* @param points the storage of all points.
|
||||
* @param normals the storage of all normals, corresponding to points.
|
||||
*/
|
||||
CV_WRAP void fetchPointsNormals(OutputArray points, OutputArray normals) const;
|
||||
/** @brief Extract the all data from volume.
|
||||
* @param points the storage of all points.
|
||||
* @param normals the storage of all normals, corresponding to points.
|
||||
* @param colors the storage of all colors, corresponding to points (only for ColorTSDF).
|
||||
*/
|
||||
CV_WRAP void fetchPointsNormalsColors(OutputArray points, OutputArray normals, OutputArray colors) const;
|
||||
|
||||
/** @brief clear all data in volume.
|
||||
*/
|
||||
CV_WRAP void reset();
|
||||
|
||||
//TODO: remove this
|
||||
/** @brief return visible blocks in volume.
|
||||
*/
|
||||
CV_WRAP int getVisibleBlocks() const;
|
||||
|
||||
/** @brief return number of volume units in volume.
|
||||
*/
|
||||
CV_WRAP size_t getTotalVolumeUnits() const;
|
||||
|
||||
enum BoundingBoxPrecision
|
||||
{
|
||||
VOLUME_UNIT = 0,
|
||||
VOXEL = 1
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Gets bounding box in volume coordinates with given precision:
|
||||
* VOLUME_UNIT - up to volume unit
|
||||
* VOXEL - up to voxel (currently not supported)
|
||||
* @param bb 6-float 1d array containing (min_x, min_y, min_z, max_x, max_y, max_z) in volume coordinates
|
||||
* @param precision bounding box calculation precision
|
||||
*/
|
||||
CV_WRAP void getBoundingBox(OutputArray bb, int precision) const;
|
||||
|
||||
/**
|
||||
* @brief Enables or disables new volume unit allocation during integration.
|
||||
* Makes sense for HashTSDF only.
|
||||
*/
|
||||
CV_WRAP void setEnableGrowth(bool v);
|
||||
/**
|
||||
* @brief Returns if new volume units are allocated during integration or not.
|
||||
* Makes sense for HashTSDF only.
|
||||
*/
|
||||
CV_WRAP bool getEnableGrowth() const;
|
||||
|
||||
class Impl;
|
||||
private:
|
||||
Ptr<Impl> impl;
|
||||
};
|
||||
|
||||
} // namespace cv
|
||||
#endif // include guard
|
||||
@@ -0,0 +1,208 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html
|
||||
|
||||
|
||||
#ifndef OPENCV_3D_VOLUME_SETTINGS_HPP
|
||||
#define OPENCV_3D_VOLUME_SETTINGS_HPP
|
||||
|
||||
#include <opencv2/core.hpp>
|
||||
#include <opencv2/geometry/volume.hpp>
|
||||
|
||||
namespace cv
|
||||
{
|
||||
|
||||
enum class VolumeType
|
||||
{
|
||||
TSDF = 0,
|
||||
HashTSDF = 1,
|
||||
ColorTSDF = 2
|
||||
};
|
||||
|
||||
|
||||
class CV_EXPORTS_W_SIMPLE VolumeSettings
|
||||
{
|
||||
public:
|
||||
/** @brief Constructor of settings for custom Volume type.
|
||||
* @param volumeType volume type.
|
||||
*/
|
||||
CV_WRAP explicit VolumeSettings(VolumeType volumeType = VolumeType::TSDF);
|
||||
|
||||
VolumeSettings(const VolumeSettings& vs);
|
||||
VolumeSettings& operator=(const VolumeSettings&);
|
||||
~VolumeSettings();
|
||||
|
||||
/** @brief Sets the width of the image for integration.
|
||||
* @param val input value.
|
||||
*/
|
||||
CV_WRAP void setIntegrateWidth(int val);
|
||||
|
||||
/** @brief Returns the width of the image for integration.
|
||||
*/
|
||||
CV_WRAP int getIntegrateWidth() const;
|
||||
|
||||
/** @brief Sets the height of the image for integration.
|
||||
* @param val input value.
|
||||
*/
|
||||
CV_WRAP void setIntegrateHeight(int val);
|
||||
|
||||
/** @brief Returns the height of the image for integration.
|
||||
*/
|
||||
CV_WRAP int getIntegrateHeight() const;
|
||||
|
||||
/** @brief Sets the width of the raycasted image, used when user does not provide it at raycast() call.
|
||||
* @param val input value.
|
||||
*/
|
||||
CV_WRAP void setRaycastWidth(int val);
|
||||
|
||||
/** @brief Returns the width of the raycasted image, used when user does not provide it at raycast() call.
|
||||
*/
|
||||
CV_WRAP int getRaycastWidth() const;
|
||||
|
||||
/** @brief Sets the height of the raycasted image, used when user does not provide it at raycast() call.
|
||||
* @param val input value.
|
||||
*/
|
||||
CV_WRAP void setRaycastHeight(int val);
|
||||
|
||||
/** @brief Returns the height of the raycasted image, used when user does not provide it at raycast() call.
|
||||
*/
|
||||
CV_WRAP int getRaycastHeight() const;
|
||||
|
||||
/** @brief Sets depth factor, witch is the number for depth scaling.
|
||||
* @param val input value.
|
||||
*/
|
||||
CV_WRAP void setDepthFactor(float val);
|
||||
|
||||
/** @brief Returns depth factor, witch is the number for depth scaling.
|
||||
*/
|
||||
CV_WRAP float getDepthFactor() const;
|
||||
|
||||
/** @brief Sets the size of voxel.
|
||||
* @param val input value.
|
||||
*/
|
||||
CV_WRAP void setVoxelSize(float val);
|
||||
|
||||
/** @brief Returns the size of voxel.
|
||||
*/
|
||||
CV_WRAP float getVoxelSize() const;
|
||||
|
||||
/** @brief Sets TSDF truncation distance. Distances greater than value from surface will be truncated to 1.0.
|
||||
* @param val input value.
|
||||
*/
|
||||
CV_WRAP void setTsdfTruncateDistance(float val);
|
||||
|
||||
/** @brief Returns TSDF truncation distance. Distances greater than value from surface will be truncated to 1.0.
|
||||
*/
|
||||
CV_WRAP float getTsdfTruncateDistance() const;
|
||||
|
||||
/** @brief Sets threshold for depth truncation in meters. Truncates the depth greater than threshold to 0.
|
||||
* @param val input value.
|
||||
*/
|
||||
CV_WRAP void setMaxDepth(float val);
|
||||
|
||||
/** @brief Returns threshold for depth truncation in meters. Truncates the depth greater than threshold to 0.
|
||||
*/
|
||||
CV_WRAP float getMaxDepth() const;
|
||||
|
||||
/** @brief Sets max number of frames to integrate per voxel.
|
||||
Represents the max number of frames over which a running average of the TSDF is calculated for a voxel.
|
||||
* @param val input value.
|
||||
*/
|
||||
CV_WRAP void setMaxWeight(int val);
|
||||
|
||||
/** @brief Returns max number of frames to integrate per voxel.
|
||||
Represents the max number of frames over which a running average of the TSDF is calculated for a voxel.
|
||||
*/
|
||||
CV_WRAP int getMaxWeight() const;
|
||||
|
||||
/** @brief Sets length of single raycast step.
|
||||
Describes the percentage of voxel length that is skipped per march.
|
||||
* @param val input value.
|
||||
*/
|
||||
CV_WRAP void setRaycastStepFactor(float val);
|
||||
|
||||
/** @brief Returns length of single raycast step.
|
||||
Describes the percentage of voxel length that is skipped per march.
|
||||
*/
|
||||
CV_WRAP float getRaycastStepFactor() const;
|
||||
|
||||
/** @brief Sets volume pose.
|
||||
* @param val input value.
|
||||
*/
|
||||
CV_WRAP void setVolumePose(InputArray val);
|
||||
|
||||
/** @brief Sets volume pose.
|
||||
* @param val output value.
|
||||
*/
|
||||
CV_WRAP void getVolumePose(OutputArray val) const;
|
||||
|
||||
/** @brief Resolution of voxel space.
|
||||
Number of voxels in each dimension.
|
||||
Applicable only for TSDF Volume.
|
||||
HashTSDF volume only supports equal resolution in all three dimensions.
|
||||
* @param val input value.
|
||||
*/
|
||||
CV_WRAP void setVolumeResolution(InputArray val);
|
||||
|
||||
/** @brief Resolution of voxel space.
|
||||
Number of voxels in each dimension.
|
||||
Applicable only for TSDF Volume.
|
||||
HashTSDF volume only supports equal resolution in all three dimensions.
|
||||
* @param val output value.
|
||||
*/
|
||||
CV_WRAP void getVolumeResolution(OutputArray val) const;
|
||||
|
||||
/** @brief Returns 3 integers representing strides by x, y and z dimension.
|
||||
Can be used to iterate over raw volume unit data.
|
||||
* @param val output value.
|
||||
*/
|
||||
CV_WRAP void getVolumeStrides(OutputArray val) const;
|
||||
|
||||
/** @brief Sets intrinsics of camera for integrations.
|
||||
* Format of input:
|
||||
* [ fx 0 cx ]
|
||||
* [ 0 fy cy ]
|
||||
* [ 0 0 1 ]
|
||||
* where fx and fy are focus points of Ox and Oy axises, and cx and cy are central points of Ox and Oy axises.
|
||||
* @param val input value.
|
||||
*/
|
||||
CV_WRAP void setCameraIntegrateIntrinsics(InputArray val);
|
||||
|
||||
/** @brief Returns intrinsics of camera for integrations.
|
||||
* Format of output:
|
||||
* [ fx 0 cx ]
|
||||
* [ 0 fy cy ]
|
||||
* [ 0 0 1 ]
|
||||
* where fx and fy are focus points of Ox and Oy axises, and cx and cy are central points of Ox and Oy axises.
|
||||
* @param val output value.
|
||||
*/
|
||||
CV_WRAP void getCameraIntegrateIntrinsics(OutputArray val) const;
|
||||
|
||||
/** @brief Sets camera intrinsics for raycast image which, used when user does not provide them at raycast() call.
|
||||
* Format of input:
|
||||
* [ fx 0 cx ]
|
||||
* [ 0 fy cy ]
|
||||
* [ 0 0 1 ]
|
||||
* where fx and fy are focus points of Ox and Oy axises, and cx and cy are central points of Ox and Oy axises.
|
||||
* @param val input value.
|
||||
*/
|
||||
CV_WRAP void setCameraRaycastIntrinsics(InputArray val);
|
||||
|
||||
/** @brief Returns camera intrinsics for raycast image, used when user does not provide them at raycast() call.
|
||||
* Format of output:
|
||||
* [ fx 0 cx ]
|
||||
* [ 0 fy cy ]
|
||||
* [ 0 0 1 ]
|
||||
* where fx and fy are focus points of Ox and Oy axises, and cx and cy are central points of Ox and Oy axises.
|
||||
* @param val output value.
|
||||
*/
|
||||
CV_WRAP void getCameraRaycastIntrinsics(OutputArray val) const;
|
||||
|
||||
class Impl;
|
||||
private:
|
||||
Ptr<Impl> impl;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // !OPENCV_3D_VOLUME_SETTINGS_HPP
|
||||
Reference in New Issue
Block a user