added drawMatches function to features2d and documentation on this
This commit is contained in:
parent
217842b0b9
commit
17a8050fe2
@ -1957,4 +1957,72 @@ protected:
|
||||
};
|
||||
\end{lstlisting}
|
||||
|
||||
\cvCppFunc{drawMatches}
|
||||
This function draws matches of keypints from two images on output image.
|
||||
Match is a line connecting two keypoints (circles).
|
||||
|
||||
\cvdefCpp{
|
||||
void drawMatches( const Mat\& img1, const Mat\& img2,
|
||||
const vector<KeyPoint>\& keypoints1, const vector<KeyPoint>\& keypoints2,
|
||||
const vector<int>\& matches, const vector<char>\& mask, Mat\& outImg,
|
||||
const Scalar\& matchColor = Scalar::all(-1),
|
||||
const Scalar\& singlePointColor = Scalar::all(-1),
|
||||
int flags = DrawMatchesFlags::DEFAULT );
|
||||
}
|
||||
|
||||
\begin{description}
|
||||
\cvarg{img1}{First sourse image.}
|
||||
\end{description}
|
||||
|
||||
\begin{description}
|
||||
\cvarg{img1}{Second sourse image.}
|
||||
\end{description}
|
||||
|
||||
\begin{description}
|
||||
\cvarg{keypoints1}{Keypoints from first sourse image.}
|
||||
\end{description}
|
||||
|
||||
\begin{description}
|
||||
\cvarg{keypoints2}{Keypoints from second sourse image.}
|
||||
\end{description}
|
||||
|
||||
\begin{description}
|
||||
\cvarg{matches}{Matches from first image to second one, i.e. keypoints1[i] has corresponding point keypoints2[matches[i]]}
|
||||
\end{description}
|
||||
|
||||
\begin{description}
|
||||
\cvarg{mask}{Mask determining which matches will be drawn. If mask is empty all matches will be drawn. }
|
||||
\end{description}
|
||||
|
||||
\begin{description}
|
||||
\cvarg{outImg}{Output image. Its content depends on \texttt{flags} value what is drawn in output image. See below possible \texttt{flags} bit values. }
|
||||
\end{description}
|
||||
|
||||
\begin{description}
|
||||
\cvarg{matchColor}{Color of matches (lines and connected keypoints). If \texttt{matchColor}==Scalar::all(-1) color will be generated randomly.}
|
||||
\end{description}
|
||||
|
||||
\begin{description}
|
||||
\cvarg{singlePointColor}{Color of single keypoints (circles), i.e. keypoints not having the matches. If \texttt{singlePointColor}==Scalar::all(-1) color will be generated randomly.}
|
||||
\end{description}
|
||||
|
||||
\begin{description}
|
||||
\cvarg{flags}{Each bit of \texttt{flags} sets some feature of drawing. Possible \texttt{flags} bit values is defined by DrawMatchesFlags, see below. }
|
||||
\end{description}
|
||||
|
||||
\begin{lstlisting}
|
||||
struct DrawMatchesFlags
|
||||
{
|
||||
enum{ DEFAULT = 0, // Output image matrix will be created (Mat::create),
|
||||
// i.e. existing memory of output image will be reused.
|
||||
// Two source image, matches and single keypoints will be drawn.
|
||||
DRAW_OVER_OUTIMG = 1, // Output image matrix will not be created (Mat::create).
|
||||
// Matches will be drawn on existing content
|
||||
// of output image.
|
||||
NOT_DRAW_SINGLE_POINTS = 2 // Single keypoints will not be drawn.
|
||||
};
|
||||
};
|
||||
|
||||
\end{lstlisting}
|
||||
|
||||
\fi
|
||||
|
@ -2121,6 +2121,24 @@ protected:
|
||||
//vector<int> classIds;
|
||||
};
|
||||
|
||||
struct CV_EXPORTS DrawMatchesFlags
|
||||
{
|
||||
enum{ DEFAULT = 0, // Output image matrix will be created (Mat::create),
|
||||
// i.e. existing memory of output image will be reused.
|
||||
// Two source image, matches and single keypoints will be drawn.
|
||||
DRAW_OVER_OUTIMG = 1, // Output image matrix will not be created (Mat::create).
|
||||
// Matches will be drawn on existing content of output image.
|
||||
NOT_DRAW_SINGLE_POINTS = 2 // Single keypoints will not be drawn.
|
||||
};
|
||||
};
|
||||
|
||||
// Draws matches of keypints from two images on output image.
|
||||
CV_EXPORTS void drawMatches( const Mat& img1, const Mat& img2,
|
||||
const vector<KeyPoint>& keypoints1, const vector<KeyPoint>& keypoints2,
|
||||
const vector<int>& matches, const vector<char>& mask, Mat& outImg,
|
||||
const Scalar& matchColor = Scalar::all(-1), const Scalar& singlePointColor = Scalar::all(-1),
|
||||
int flags = DrawMatchesFlags::DEFAULT );
|
||||
|
||||
}
|
||||
|
||||
#endif /* __cplusplus */
|
||||
|
@ -44,7 +44,66 @@
|
||||
using namespace std;
|
||||
using namespace cv;
|
||||
|
||||
//#define _KDTREE
|
||||
CV_EXPORTS void cv::drawMatches( const Mat& img1, const Mat& img2,
|
||||
const vector<KeyPoint>& keypoints1, const vector<KeyPoint>& keypoints2,
|
||||
const vector<int>& matches, const vector<char>& mask, Mat& outImg,
|
||||
const Scalar& matchColor, const Scalar& singlePointColor,
|
||||
int flags )
|
||||
{
|
||||
Size size( img1.cols + img2.cols, MAX(img1.rows, img2.rows) );
|
||||
if( flags & DrawMatchesFlags::DRAW_OVER_OUTIMG )
|
||||
{
|
||||
if( size.width > outImg.cols || size.height > outImg.rows )
|
||||
CV_Error( CV_StsBadSize, "outImg has size less than need to draw img1 and img2 together" );
|
||||
}
|
||||
else
|
||||
{
|
||||
outImg.create( size, CV_MAKETYPE(img1.depth(), 3) );
|
||||
Mat outImg1 = outImg( Rect(0, 0, img1.cols, img1.rows) );
|
||||
cvtColor( img1, outImg1, CV_GRAY2RGB );
|
||||
Mat outImg2 = outImg( Rect(img1.cols, 0, img2.cols, img2.rows) );
|
||||
cvtColor( img2, outImg2, CV_GRAY2RGB );
|
||||
}
|
||||
|
||||
RNG rng;
|
||||
// draw keypoints
|
||||
if( !(flags & DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS) )
|
||||
{
|
||||
bool isRandSinglePointColor = singlePointColor == Scalar::all(-1);
|
||||
for( vector<KeyPoint>::const_iterator it = keypoints1.begin(); it < keypoints1.end(); ++it )
|
||||
{
|
||||
circle( outImg, it->pt, 3, isRandSinglePointColor ?
|
||||
Scalar(rng.uniform(0, 256), rng.uniform(0, 256), rng.uniform(0, 256)) : singlePointColor );
|
||||
}
|
||||
for( vector<KeyPoint>::const_iterator it = keypoints2.begin(); it < keypoints2.end(); ++it )
|
||||
{
|
||||
Point p = it->pt;
|
||||
circle( outImg, Point2f(p.x+img1.cols, p.y), 3, isRandSinglePointColor ?
|
||||
Scalar(rng.uniform(0, 256), rng.uniform(0, 256), rng.uniform(0, 256)) : singlePointColor );
|
||||
}
|
||||
}
|
||||
|
||||
// draw matches
|
||||
bool isRandMatchColor = matchColor == Scalar::all(-1);
|
||||
if( matches.size() != keypoints1.size() )
|
||||
CV_Error( CV_StsBadSize, "matches must have the same size as keypoints1" );
|
||||
if( !mask.empty() && mask.size() != keypoints1.size() )
|
||||
CV_Error( CV_StsBadSize, "mask must have the same size as keypoints1" );
|
||||
vector<int>::const_iterator mit = matches.begin();
|
||||
for( int i1 = 0; mit != matches.end(); ++mit, i1++ )
|
||||
{
|
||||
if( (mask.empty() || mask[i1] ) && *mit >= 0 )
|
||||
{
|
||||
Point2f pt1 = keypoints1[i1].pt,
|
||||
pt2 = keypoints2[*mit].pt,
|
||||
dpt2 = Point2f( std::min(pt2.x+img1.cols, float(outImg.cols-1)), pt2.y );
|
||||
Scalar randColor( rng.uniform(0, 256), rng.uniform(0, 256), rng.uniform(0, 256) );
|
||||
circle( outImg, pt1, 3, isRandMatchColor ? randColor : matchColor );
|
||||
circle( outImg, dpt2, 3, isRandMatchColor ? randColor : matchColor );
|
||||
line( outImg, pt1, dpt2, isRandMatchColor ? randColor : matchColor );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************************\
|
||||
* DescriptorExtractor *
|
||||
|
Loading…
x
Reference in New Issue
Block a user