handling Ptr<> arguments and return values in Python wrappers
partially wrapped features2d framework added feature_homography.py sample
This commit is contained in:
parent
2ef4e2eeb7
commit
d50cc51070
@ -1378,7 +1378,7 @@ protected:
|
||||
/*
|
||||
* Abstract base class for 2D image feature detectors.
|
||||
*/
|
||||
class CV_EXPORTS FeatureDetector
|
||||
class CV_EXPORTS_W FeatureDetector
|
||||
{
|
||||
public:
|
||||
virtual ~FeatureDetector();
|
||||
@ -1390,7 +1390,7 @@ public:
|
||||
* mask Mask specifying where to look for keypoints (optional). Must be a char
|
||||
* matrix with non-zero values in the region of interest.
|
||||
*/
|
||||
void detect( const Mat& image, vector<KeyPoint>& keypoints, const Mat& mask=Mat() ) const;
|
||||
CV_WRAP void detect( const Mat& image, CV_OUT vector<KeyPoint>& keypoints, const Mat& mask=Mat() ) const;
|
||||
|
||||
/*
|
||||
* Detect keypoints in an image set.
|
||||
@ -1406,10 +1406,10 @@ public:
|
||||
virtual void write( FileStorage& ) const;
|
||||
|
||||
// Return true if detector object is empty
|
||||
virtual bool empty() const;
|
||||
CV_WRAP virtual bool empty() const;
|
||||
|
||||
// Create feature detector by detector name.
|
||||
static Ptr<FeatureDetector> create( const string& detectorType );
|
||||
CV_WRAP static Ptr<FeatureDetector> create( const string& detectorType );
|
||||
|
||||
protected:
|
||||
virtual void detectImpl( const Mat& image, vector<KeyPoint>& keypoints, const Mat& mask=Mat() ) const = 0;
|
||||
@ -1422,10 +1422,10 @@ protected:
|
||||
static void removeInvalidPoints( const Mat& mask, vector<KeyPoint>& keypoints );
|
||||
};
|
||||
|
||||
class CV_EXPORTS FastFeatureDetector : public FeatureDetector
|
||||
class CV_EXPORTS_W FastFeatureDetector : public FeatureDetector
|
||||
{
|
||||
public:
|
||||
FastFeatureDetector( int threshold=10, bool nonmaxSuppression=true );
|
||||
CV_WRAP FastFeatureDetector( int threshold=10, bool nonmaxSuppression=true );
|
||||
virtual void read( const FileNode& fn );
|
||||
virtual void write( FileStorage& fs ) const;
|
||||
|
||||
@ -1673,11 +1673,11 @@ protected:
|
||||
* Adapts a detector to detect points over multiple levels of a Gaussian
|
||||
* pyramid. Useful for detectors that are not inherently scaled.
|
||||
*/
|
||||
class CV_EXPORTS PyramidAdaptedFeatureDetector : public FeatureDetector
|
||||
class CV_EXPORTS_W PyramidAdaptedFeatureDetector : public FeatureDetector
|
||||
{
|
||||
public:
|
||||
// maxLevel - The 0-based index of the last pyramid layer
|
||||
PyramidAdaptedFeatureDetector( const Ptr<FeatureDetector>& detector, int maxLevel=2 );
|
||||
CV_WRAP PyramidAdaptedFeatureDetector( const Ptr<FeatureDetector>& detector, int maxLevel=2 );
|
||||
|
||||
// TODO implement read/write
|
||||
virtual bool empty() const;
|
||||
@ -1835,7 +1835,7 @@ CV_EXPORTS Mat windowedMatchingMask( const vector<KeyPoint>& keypoints1, const v
|
||||
* distances between descriptors. Therefore we represent a collection of
|
||||
* descriptors as a cv::Mat, where each row is one keypoint descriptor.
|
||||
*/
|
||||
class CV_EXPORTS DescriptorExtractor
|
||||
class CV_EXPORTS_W DescriptorExtractor
|
||||
{
|
||||
public:
|
||||
virtual ~DescriptorExtractor();
|
||||
@ -1846,7 +1846,7 @@ public:
|
||||
* keypoints The input keypoints. Keypoints for which a descriptor cannot be computed are removed.
|
||||
* descriptors Copmputed descriptors. Row i is the descriptor for keypoint i.
|
||||
*/
|
||||
void compute( const Mat& image, vector<KeyPoint>& keypoints, Mat& descriptors ) const;
|
||||
CV_WRAP void compute( const Mat& image, CV_IN_OUT vector<KeyPoint>& keypoints, CV_OUT Mat& descriptors ) const;
|
||||
|
||||
/*
|
||||
* Compute the descriptors for a keypoints collection detected in image collection.
|
||||
@ -1860,12 +1860,12 @@ public:
|
||||
virtual void read( const FileNode& );
|
||||
virtual void write( FileStorage& ) const;
|
||||
|
||||
virtual int descriptorSize() const = 0;
|
||||
virtual int descriptorType() const = 0;
|
||||
CV_WRAP virtual int descriptorSize() const = 0;
|
||||
CV_WRAP virtual int descriptorType() const = 0;
|
||||
|
||||
virtual bool empty() const;
|
||||
CV_WRAP virtual bool empty() const;
|
||||
|
||||
static Ptr<DescriptorExtractor> create( const string& descriptorExtractorType );
|
||||
CV_WRAP static Ptr<DescriptorExtractor> create( const string& descriptorExtractorType );
|
||||
|
||||
protected:
|
||||
virtual void computeImpl( const Mat& image, vector<KeyPoint>& keypoints, Mat& descriptors ) const = 0;
|
||||
@ -2201,19 +2201,19 @@ struct CV_EXPORTS Hamming
|
||||
/*
|
||||
* Struct for matching: query descriptor index, train descriptor index, train image index and distance between descriptors.
|
||||
*/
|
||||
struct CV_EXPORTS DMatch
|
||||
struct CV_EXPORTS_W_SIMPLE DMatch
|
||||
{
|
||||
DMatch() : queryIdx(-1), trainIdx(-1), imgIdx(-1), distance(std::numeric_limits<float>::max()) {}
|
||||
DMatch( int _queryIdx, int _trainIdx, float _distance ) :
|
||||
CV_WRAP DMatch() : queryIdx(-1), trainIdx(-1), imgIdx(-1), distance(std::numeric_limits<float>::max()) {}
|
||||
CV_WRAP DMatch( int _queryIdx, int _trainIdx, float _distance ) :
|
||||
queryIdx(_queryIdx), trainIdx(_trainIdx), imgIdx(-1), distance(_distance) {}
|
||||
DMatch( int _queryIdx, int _trainIdx, int _imgIdx, float _distance ) :
|
||||
CV_WRAP DMatch( int _queryIdx, int _trainIdx, int _imgIdx, float _distance ) :
|
||||
queryIdx(_queryIdx), trainIdx(_trainIdx), imgIdx(_imgIdx), distance(_distance) {}
|
||||
|
||||
int queryIdx; // query descriptor index
|
||||
int trainIdx; // train descriptor index
|
||||
int imgIdx; // train image index
|
||||
CV_PROP_RW int queryIdx; // query descriptor index
|
||||
CV_PROP_RW int trainIdx; // train descriptor index
|
||||
CV_PROP_RW int imgIdx; // train image index
|
||||
|
||||
float distance;
|
||||
CV_PROP_RW float distance;
|
||||
|
||||
// less is better
|
||||
bool operator<( const DMatch &m ) const
|
||||
@ -2228,7 +2228,7 @@ struct CV_EXPORTS DMatch
|
||||
/*
|
||||
* Abstract base class for matching two sets of descriptors.
|
||||
*/
|
||||
class CV_EXPORTS DescriptorMatcher
|
||||
class CV_EXPORTS_W DescriptorMatcher
|
||||
{
|
||||
public:
|
||||
virtual ~DescriptorMatcher();
|
||||
@ -2273,14 +2273,14 @@ public:
|
||||
* Method train() is run in this methods.
|
||||
*/
|
||||
// Find one best match for each query descriptor (if mask is empty).
|
||||
void match( const Mat& queryDescriptors, const Mat& trainDescriptors,
|
||||
vector<DMatch>& matches, const Mat& mask=Mat() ) const;
|
||||
CV_WRAP void match( const Mat& queryDescriptors, const Mat& trainDescriptors,
|
||||
CV_OUT vector<DMatch>& matches, const Mat& mask=Mat() ) const;
|
||||
// Find k best matches for each query descriptor (in increasing order of distances).
|
||||
// compactResult is used when mask is not empty. If compactResult is false matches
|
||||
// vector will have the same size as queryDescriptors rows. If compactResult is true
|
||||
// matches vector will not contain matches for fully masked out query descriptors.
|
||||
void knnMatch( const Mat& queryDescriptors, const Mat& trainDescriptors,
|
||||
vector<vector<DMatch> >& matches, int k,
|
||||
CV_WRAP void knnMatch( const Mat& queryDescriptors, const Mat& trainDescriptors,
|
||||
CV_OUT vector<vector<DMatch> >& matches, int k,
|
||||
const Mat& mask=Mat(), bool compactResult=false ) const;
|
||||
// Find best matches for each query descriptor which have distance less than
|
||||
// maxDistance (in increasing order of distances).
|
||||
@ -2308,7 +2308,7 @@ public:
|
||||
// but with empty train data.
|
||||
virtual Ptr<DescriptorMatcher> clone( bool emptyTrainData=false ) const = 0;
|
||||
|
||||
static Ptr<DescriptorMatcher> create( const string& descriptorMatcherType );
|
||||
CV_WRAP static Ptr<DescriptorMatcher> create( const string& descriptorMatcherType );
|
||||
protected:
|
||||
/*
|
||||
* Class to work with descriptors from several images as with one merged matrix.
|
||||
|
@ -64,9 +64,15 @@ typedef vector<Vec4i> vector_Vec4i;
|
||||
typedef vector<Rect> vector_Rect;
|
||||
typedef vector<KeyPoint> vector_KeyPoint;
|
||||
typedef vector<Mat> vector_Mat;
|
||||
typedef vector<DMatch> vector_DMatch;
|
||||
typedef vector<vector<Point> > vector_vector_Point;
|
||||
typedef vector<vector<Point2f> > vector_vector_Point2f;
|
||||
typedef vector<vector<Point3f> > vector_vector_Point3f;
|
||||
typedef vector<vector<DMatch> > vector_vector_DMatch;
|
||||
|
||||
typedef Ptr<FeatureDetector> Ptr_FeatureDetector;
|
||||
typedef Ptr<DescriptorExtractor> Ptr_DescriptorExtractor;
|
||||
typedef Ptr<DescriptorMatcher> Ptr_DescriptorMatcher;
|
||||
|
||||
static PyObject* failmsgp(const char *fmt, ...)
|
||||
{
|
||||
@ -312,6 +318,14 @@ static PyObject* pyopencv_from(size_t value)
|
||||
return PyLong_FromUnsignedLong((unsigned long)value);
|
||||
}
|
||||
|
||||
static bool pyopencv_to(PyObject* obj, size_t& value, const char* name = "<unknown>")
|
||||
{
|
||||
if(!obj || obj == Py_None)
|
||||
return true;
|
||||
value = (int)PyLong_AsUnsignedLong(obj);
|
||||
return value != -1 || !PyErr_Occurred();
|
||||
}
|
||||
|
||||
static PyObject* pyopencv_from(int value)
|
||||
{
|
||||
return PyInt_FromLong(value);
|
||||
@ -605,6 +619,7 @@ template<typename _Tp> static inline PyObject* pyopencv_from(const vector<_Tp>&
|
||||
}
|
||||
|
||||
static PyObject* pyopencv_from(const KeyPoint&);
|
||||
static PyObject* pyopencv_from(const DMatch&);
|
||||
|
||||
template<typename _Tp> static inline bool pyopencv_to_generic_vec(PyObject* obj, vector<_Tp>& value, const char* name="<unknown>")
|
||||
{
|
||||
@ -689,6 +704,19 @@ template<> struct pyopencvVecConverter<KeyPoint>
|
||||
}
|
||||
};
|
||||
|
||||
template<> struct pyopencvVecConverter<DMatch>
|
||||
{
|
||||
static bool to(PyObject* obj, vector<DMatch>& value, const char* name="<unknown>")
|
||||
{
|
||||
return pyopencv_to_generic_vec(obj, value, name);
|
||||
}
|
||||
|
||||
static PyObject* from(const vector<DMatch>& value)
|
||||
{
|
||||
return pyopencv_from_generic_vec(value);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
static inline bool pyopencv_to(PyObject *obj, CvTermCriteria& dst, const char *name="<unknown>")
|
||||
{
|
||||
|
@ -7,7 +7,11 @@ gen_template_check_self = Template(""" if(!PyObject_TypeCheck(self, &pyopencv
|
||||
""")
|
||||
|
||||
gen_template_call_constructor = Template("""self = PyObject_NEW(pyopencv_${name}_t, &pyopencv_${name}_Type);
|
||||
if(self) ERRWRAP2(self->v = $op$cname""")
|
||||
new (&(self->v)) Ptr<$cname>(); // init Ptr with placement new
|
||||
if(self) ERRWRAP2(self->v = new $cname""")
|
||||
|
||||
gen_template_simple_call_constructor = Template("""self = PyObject_NEW(pyopencv_${name}_t, &pyopencv_${name}_Type);
|
||||
if(self) ERRWRAP2(self->v = $cname""")
|
||||
|
||||
gen_template_parse_args = Template("""const char* keywords[] = { $kw_list, NULL };
|
||||
if( PyArg_ParseTupleAndKeywords(args, kw, "$fmtspec", (char**)keywords, $parse_arglist)$code_cvt )""")
|
||||
@ -66,7 +70,7 @@ gen_template_type_decl = Template("""
|
||||
struct pyopencv_${name}_t
|
||||
{
|
||||
PyObject_HEAD
|
||||
${cname}* v;
|
||||
Ptr<${cname}> v;
|
||||
};
|
||||
|
||||
static PyTypeObject pyopencv_${name}_Type =
|
||||
@ -79,9 +83,31 @@ static PyTypeObject pyopencv_${name}_Type =
|
||||
|
||||
static void pyopencv_${name}_dealloc(PyObject* self)
|
||||
{
|
||||
delete ((pyopencv_${name}_t*)self)->v;
|
||||
((pyopencv_${name}_t*)self)->v = NULL;
|
||||
PyObject_Del(self);
|
||||
}
|
||||
|
||||
static PyObject* pyopencv_from(const Ptr<${cname}>& r)
|
||||
{
|
||||
pyopencv_${name}_t *m = PyObject_NEW(pyopencv_${name}_t, &pyopencv_${name}_Type);
|
||||
new (&(m->v)) Ptr<$cname>(); // init Ptr with placement new
|
||||
m->v = r;
|
||||
return (PyObject*)m;
|
||||
}
|
||||
|
||||
static bool pyopencv_to(PyObject* src, Ptr<${cname}>& dst, const char* name="<unknown>")
|
||||
{
|
||||
if( src == NULL || src == Py_None )
|
||||
return true;
|
||||
if(!PyObject_TypeCheck(src, &pyopencv_${name}_Type))
|
||||
{
|
||||
failmsg("Expected ${cname} for argument '%s'", name);
|
||||
return false;
|
||||
}
|
||||
dst = ((pyopencv_${name}_t*)src)->v;
|
||||
return true;
|
||||
}
|
||||
|
||||
""")
|
||||
|
||||
gen_template_map_type_cvt = Template("""
|
||||
@ -490,10 +516,10 @@ class FuncInfo(object):
|
||||
|
||||
if self.isconstructor:
|
||||
code_decl += " pyopencv_%s_t* self = 0;\n" % selfinfo.name
|
||||
op = "new "
|
||||
templ = gen_template_call_constructor
|
||||
if selfinfo.issimple:
|
||||
op = ""
|
||||
code_fcall = gen_template_call_constructor.substitute(name=selfinfo.name, cname=selfinfo.cname, op=op)
|
||||
templ = gen_template_simple_call_constructor
|
||||
code_fcall = templ.substitute(name=selfinfo.name, cname=selfinfo.cname)
|
||||
else:
|
||||
code_fcall = "ERRWRAP2( "
|
||||
if v.rettype:
|
||||
|
73
samples/python2/feature_homography.py
Normal file
73
samples/python2/feature_homography.py
Normal file
@ -0,0 +1,73 @@
|
||||
'''
|
||||
Feature homography
|
||||
==================
|
||||
|
||||
Example of using features2d framework for interactive video homography matching.
|
||||
|
||||
Keys
|
||||
----
|
||||
SPACE - set reference frame
|
||||
ESC - exit
|
||||
'''
|
||||
|
||||
import numpy as np
|
||||
import cv2
|
||||
import video
|
||||
from common import draw_str
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
print __doc__
|
||||
|
||||
detector = cv2.FeatureDetector_create('ORB')
|
||||
extractor = cv2.DescriptorExtractor_create('ORB')
|
||||
matcher = cv2.DescriptorMatcher_create('BruteForce-Hamming') # 'BruteForce-Hamming' # FlannBased
|
||||
|
||||
ref_desc = None
|
||||
ref_kp = None
|
||||
|
||||
green, red = (0, 255, 0), (0, 0, 255)
|
||||
|
||||
cap = video.create_capture(0)
|
||||
while True:
|
||||
ret, img = cap.read()
|
||||
vis = img.copy()
|
||||
kp = detector.detect(img)
|
||||
|
||||
for p in kp:
|
||||
x, y = np.int32(p.pt)
|
||||
r = int(0.5*p.size)
|
||||
cv2.circle(vis, (x, y), r, (0, 255, 0))
|
||||
draw_str(vis, (20, 20), 'feature_n: %d' % len(kp))
|
||||
|
||||
desc = extractor.compute(img, kp)
|
||||
if ref_desc is not None:
|
||||
raw_matches = matcher.knnMatch(desc, ref_desc, 2)
|
||||
eps = 1e-5
|
||||
matches = [(m1.trainIdx, m1.queryIdx) for m1, m2 in raw_matches if (m1.distance+eps) / (m2.distance+eps) < 0.7]
|
||||
match_n = len(matches)
|
||||
|
||||
inliner_n = 0
|
||||
if match_n > 10:
|
||||
p0 = np.float32( [ref_kp[i].pt for i, j in matches] )
|
||||
p1 = np.float32( [kp[j].pt for i, j in matches] )
|
||||
|
||||
H, status = cv2.findHomography(p0, p1, cv2.RANSAC, 10.0)
|
||||
inlier_n = sum(status)
|
||||
if inlier_n > 10:
|
||||
for (x1, y1), (x2, y2), inlier in zip(np.int32(p0), np.int32(p1), status):
|
||||
cv2.line(vis, (x1, y1), (x2, y2), (red, green)[inlier])
|
||||
|
||||
h, w = img.shape[:2]
|
||||
overlay = cv2.warpPerspective(ref_img, H, (w, h))
|
||||
vis = cv2.addWeighted(vis, 0.5, overlay, 0.5, 0.0)
|
||||
draw_str(vis, (20, 40), 'matched: %d ( %d outliers )' % (match_n, match_n-inlier_n))
|
||||
|
||||
cv2.imshow('img', vis)
|
||||
ch = cv2.waitKey(1)
|
||||
if ch == ord(' '):
|
||||
ref_desc = desc
|
||||
ref_kp = kp
|
||||
ref_img = img.copy()
|
||||
if ch == 27:
|
||||
break
|
Loading…
x
Reference in New Issue
Block a user