From 91e0abfa1b0066a010cb6173bee064719f55559e Mon Sep 17 00:00:00 2001 From: Ed J Date: Thu, 23 Mar 2023 07:17:38 +0000 Subject: [PATCH] support RotatedRect --- Imgproc/funclist.pl | 41 +++++++++++++++++++++++++++++++++++++++++ classes.pl | 14 ++++++++++++++ funclist.pl | 2 ++ genpp.pl | 1 + maint/genlists | 26 ++++++++++++++++++++++++-- typemap | 1 + 6 files changed, 83 insertions(+), 2 deletions(-) diff --git a/Imgproc/funclist.pl b/Imgproc/funclist.pl index b2241e7..2b19d29 100644 --- a/Imgproc/funclist.pl +++ b/Imgproc/funclist.pl @@ -263,6 +263,47 @@ @param offset Optional offset by which every contour point is shifted. This is useful if the contours are extracted from the image ROI and then they should be analyzed in the whole image context.',0,'void',['Mat','image','',[]],['vector_Mat','contours','',['/O']],['Mat','hierarchy','',['/O']],['int','mode','',[]],['int','method','',[]],['Point','offset','Point()',[]]], +['','fitEllipseDirect','@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 Fitzgibbon1999 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',0,'RotatedRect',['Mat','points','',[]]], ['','rectangle','@brief Draws a simple, thick, or filled up-right rectangle. The function cv::rectangle draws a rectangle outline or a filled rectangle whose two opposite corners diff --git a/classes.pl b/classes.pl index 97096e7..3de1644 100644 --- a/classes.pl +++ b/classes.pl @@ -1,4 +1,18 @@ ( +['RotatedRect',[],'@brief The class represents rotated (i.e. not up-right) rectangles on a plane. + +Each rectangle is specified by the center point (mass center), length of each side (represented by +#Size2f structure) and the rotation angle in degrees. + +The sample below demonstrates how to use RotatedRect: +@snippet snippets/core_various.cpp RotatedRect_demo +![image](pics/rotatedrect.png) + +@sa CamShift, fitEllipse, minAreaRect, CvBox2D',0,'cv::RotatedRect',[[[],''],[[['Point2f','center','',['/C','/Ref']],['Size2f','size','',['/C','/Ref']],['float','angle','',[]]],'full constructor + @param center The rectangle mass center. + @param size Width and height of the rectangle. + @param angle The rotation angle in a clockwise direction. When the angle is 0, 90, 180, 270 etc., + the rectangle becomes an up-right rectangle.']]], ['KeyPoint',[],'@brief Data structure for salient point detectors. The class instance stores a keypoint, i.e. a point feature found by one of many available keypoint diff --git a/funclist.pl b/funclist.pl index 4831df2..b9d4d6f 100644 --- a/funclist.pl +++ b/funclist.pl @@ -1,4 +1,6 @@ ( +['RotatedRect','boundingRect','returns 4 vertices of the rectangle + @param pts The points array for storing rectangle vertices. The order is bottomLeft, topLeft, topRight, bottomRight.',1,'Rect'], ['KeyPoint','convert','This method converts vector of keypoints to vector of points or the reverse, where each keypoint is assigned the same size and the same orientation. diff --git a/genpp.pl b/genpp.pl index 11a0b44..53c496f 100644 --- a/genpp.pl +++ b/genpp.pl @@ -50,6 +50,7 @@ package PP::OpenCV; Rect=>[map ['ptrdiff_t', $_], qw(x y width height)], Scalar=>[map ['double', "v$_", "val[$_]"], 0..3], Size=>[map ['ptrdiff_t', $_], qw(width height)], + Size2f=>[map ['float', $_], qw(width height)], Vec4f=>[map ['float', "v$_", "val[$_]"], 0..3], Vec6f=>[map ['float', "v$_", "val[$_]"], 0..5], ); diff --git a/maint/genlists b/maint/genlists index db70c87..d9236c7 100755 --- a/maint/genlists +++ b/maint/genlists @@ -5,6 +5,9 @@ use warnings; use JSON::PP; use File::Basename; use File::Spec::Functions; +use File::Temp qw(tempdir); +use File::Path qw(make_path); +use File::Basename qw(dirname); use Cwd; use IPC::Open2; use Data::Dumper; @@ -21,12 +24,28 @@ EOF my @HEADERS_FILES = do { local @ARGV = $HEADERS; grep !/^\s*#/, <> }; chomp @HEADERS_FILES; +my $tdir = tempdir(CLEANUP=>1); +sub process_header { + my ($dir, $file) = @_; + open my $fh, '<', catfile($dir, $file) or die "$file: $!"; + my $outfile = catfile($tdir, $file); + my $outdir = dirname $outfile; + make_path $outdir or die "$outdir: $!" if !-d $outdir; + open my $outfh, '>', $outfile or die "$outfile: $!"; + my $intext = do { local $/; <$fh> }; + $intext =~ s/(class\s+)(CV_EXPORTS)(\s+RotatedRect)/$1${2}_W$3/; + $intext =~ s/^(\s*)(RotatedRect\((?:.*angle|\)))/${1}CV_WRAP $2/gm; + $intext =~ s/^(\s*)(.*?boundingRect\()/${1}CV_WRAP $2/m; + print $outfh $intext; + $outfile; +} + my $json_data; { my $old_dir = getcwd(); chdir $CVDIR or die "chdir: $!"; my $pid = open2(my $child_out, my $child_in, qw(python3 -c), $PYSCRIPT); -print $child_in map catfile($HEADERS_DIR, $_)."\n", @HEADERS_FILES; +print $child_in map process_header($HEADERS_DIR, $_)."\n", @HEADERS_FILES; close $child_in; $json_data = decode_json do { local $/; <$child_out> }; chdir $old_dir or die "chdir: $!"; @@ -45,11 +64,13 @@ my %force = map +($_=>1), qw( cv.FileStorage.operator[] cv.KeyPoint.overlap cv.KeyPoint.convert + cv.RotatedRect.boundingRect cv.cvtColor cv.rectangle cv.ellipse2Poly cv.getAffineTransform cv.getGaborKernel + cv.fitEllipseDirect cv.drawContours cv.findContours cv.threshold @@ -98,8 +119,9 @@ my %class = map +($_=>1), qw( CascadeClassifier Subdiv2D TrackerKCF TrackerCSRT TrackerMIL FileNode FileStorage DMatch KeyPoint Algorithm CLAHE GeneralizedHough HOGDescriptor SparsePyrLKOpticalFlow DISOpticalFlow SparseOpticalFlow + TermCriteria RNG RotatedRect ); -my $no_want = qr/^(TermCriteria|RNG|RotatedRect)/; +my $no_want = qr/^(TermCriteria|RNG)/; my $skip_re = join '|', qr/^cv\.ipp/, qr/^cv\.moments/, diff --git a/typemap b/typemap index 8641f23..9fcd069 100644 --- a/typemap +++ b/typemap @@ -6,6 +6,7 @@ vector_KeyPointWrapper* T_OPENCV_VECTOR vector_MatWrapper* T_OPENCV_VECTOR vector_StringWrapper* T_OPENCV_VECTOR vector_vector_Point2fWrapper* T_OPENCV_VECTOR +RotatedRectWrapper* T_PTROBJ_SPECIAL KeyPointWrapper* T_PTROBJ_SPECIAL DMatchWrapper* T_PTROBJ_SPECIAL FileStorageWrapper* T_PTROBJ_SPECIAL