Merge pull request #46 from lazywei/cv2

[WIP] Further wrapping based on mat64
This commit is contained in:
Chih-Wei Chang 2015-02-17 12:42:47 +08:00
commit 27d60c564a
17 changed files with 748 additions and 448 deletions

View file

@ -42,6 +42,8 @@ If you want to use CV2's API, please refer to the code under `gocv/` directory.
Please also note that the basic data structures in OpenCV (e.g., `cv::Mat`, `cv::Point3f`) are wrapped partially for now. For more detail on how to use these types, please refer to [GoCV's README](gocv/README.md). Please also note that the basic data structures in OpenCV (e.g., `cv::Mat`, `cv::Point3f`) are wrapped partially for now. For more detail on how to use these types, please refer to [GoCV's README](gocv/README.md).
*Requirement*: we will build the wrappers based on [mat64](https://godoc.org/github.com/gonum/matrix/mat64), given it is much easier to manipulate the underlaying data. In most case, it is not necessary to access the original CV data, e.g., `cv::Mat` can be converted from/to `*mat64.Dense`.
## Example ## Example
### OpenCV2's initCameraMatrix2D ### OpenCV2's initCameraMatrix2D
@ -49,22 +51,25 @@ Please also note that the basic data structures in OpenCV (e.g., `cv::Mat`, `cv:
```go ```go
package main package main
import "github.com/lazywei/go-opencv/gocv" import . "github.com/lazywei/go-opencv/gocv"
import "github.com/gonum/matrix/mat64"
func main() { func main() {
objPts := gocv.NewGcvPoint3fVector(int64(4))
objPts.Set(0, gocv.NewGcvPoint3f(0, 25, 0))
objPts.Set(1, gocv.NewGcvPoint3f(0, -25, 0))
objPts.Set(2, gocv.NewGcvPoint3f(-47, 25, 0))
objPts.Set(3, gocv.NewGcvPoint3f(-47, -25, 0))
imgPts := gocv.NewGcvPoint2fVector(int64(4)) objPts := mat64.NewDense(4, 3, []float64{
imgPts.Set(0, gocv.NewGcvPoint2f(1136.4140625, 1041.89208984)) 0, 25, 0,
imgPts.Set(1, gocv.NewGcvPoint2f(1845.33190918, 671.39581299)) 0, -25, 0,
imgPts.Set(2, gocv.NewGcvPoint2f(302.73373413, 634.79998779)) -47, 25, 0,
imgPts.Set(3, gocv.NewGcvPoint2f(1051.46154785, 352.76107788)) -47, -25, 0})
gocv.GcvInitCameraMatrix2D(objPts, imgPts) imgPts := mat64.NewDense(4, 2, []float64{
1136.4140625, 1041.89208984,
1845.33190918, 671.39581299,
302.73373413, 634.79998779,
1051.46154785, 352.76107788})
camMat := GcvInitCameraMatrix2D(objPts, imgPts)
fmt.Println(camMat)
} }
``` ```

View file

@ -6,22 +6,22 @@ Wrap the core types in OpenCV.
## Supporting Types and Examples ## Supporting Types and Examples
| OpenCV C++ | Go OpenCV | Constructor | | OpenCV C++ | Go OpenCV | Constructor |
|---------------|---------------|-------------------------------| |---------------|-----------------|-------------------------------|
| `cv::Point2i` | `GcvPoint2i` | `NewGcvPoint2i(x, y int)` | | `cv::Point2i` | `GcvPoint2i` | `NewGcvPoint2i(x, y int)` |
| `cv::Point2f` | `GcvPoint2f_` | `NewGcvPoint2f(x, y float32)` | | `cv::Point2f` | `GcvPoint2f32_` | `NewGcvPoint2f32(x, y float64)` |
| `cv::Point2d` | `GcvPoint2d_` | `NewGcvPoint2d(x, y float64)` | | `cv::Point2d` | `GcvPoint2f64_` | `NewGcvPoint2f64(x, y float64)` |
| `cv::Point3i` | `GcvPoint3i` | `NewGcvPoint3i(x, y, z int)` | | `cv::Point3i` | `GcvPoint3i` | `NewGcvPoint3i(x, y, z int)` |
| `cv::Point3f` | `GcvPoint3f_` | `NewGcvPoint3f(x, y, z float32)` | | `cv::Point3f` | `GcvPoint3f32_` | `NewGcvPoint3f32(x, y, z float64)` |
| `cv::Point3d` | `GcvPoint3d_` | `NewGcvPoint3d(x, y, z float64)` | | `cv::Point3d` | `GcvPoint3f64_` | `NewGcvPoint3f64(x, y, z float64)` |
| `cv::Size2i` | `GcvSize2i` | `NewGcvSize2i(x, y int)` | | `cv::Size2i` | `GcvSize2i` | `NewGcvSize2i(x, y int)` |
| `cv::Size2f` | `GcvSize2f_` | `NewGcvSize2f(x, y float32)` | | `cv::Size2f` | `GcvSize2f32_` | `NewGcvSize2f64(x, y float64)` |
| `cv::Size2d` | `GcvSize2d_` | `NewGcvSize2d(x, y float64)` | | `cv::Size2d` | `GcvSize2f64_` | `NewGcvSize2f64(x, y float64)` |
---------- ----------
### Note for Renamed Types ### Note for Renamed Types
Some of the types are renamed to `*_`. The reason is that we'd like to wrap a better interface for them. Some of the types are renamed to `*_`. The reason is that we'd like to wrap a better interface for them.
For example, the original `NewPoint2f` takes strictly two `float32`, and we are not able to pass `float64` or `int`, which doesn't make too much sense. For example, the original `NewGcvPoint2f32` takes strictly two `float32`, and we are not able to pass `float64` or `int`, which doesn't make too much sense.
After wrapping an extra level, we are now able to pass `int`, `float32`, and `float64` to these methods. After wrapping an extra level, we are now able to pass `int`, `float32`, and `float64` to these methods.
Also note that **renaming doesn't affect any usage**, except you are manipulating the types yourself. Also note that **renaming doesn't affect any usage**, except you are manipulating the types yourself.

View file

@ -1,44 +0,0 @@
#include <opencv2/opencv.hpp>
#include <opencv2/core/core.hpp>
#include <iostream>
#include <vector>
#include "gocv.hpp"
cv::Mat GcvInitCameraMatrix2D(VecPoint3f objPts, VecPoint2f imgPts) {
cv::Mat cameraMatrix;
std::vector<VecPoint3f> objPtsArr;
std::vector<VecPoint2f> imgPtsArr;
objPtsArr.push_back(objPts);
imgPtsArr.push_back(imgPts);
cameraMatrix = cv::initCameraMatrix2D(objPtsArr, imgPtsArr, cv::Size(1920, 1080), 1);
std::cout << cameraMatrix.type() << std::endl;
return cameraMatrix;
}
double GcvCalibrateCamera(VecPoint3f objPts, VecPoint2f imgPts,
cv::Size imgSize, cv::Mat cameraMatrix) {
std::vector<VecPoint3f> objPtsArr;
std::vector<VecPoint2f> imgPtsArr;
std::vector<cv::Mat> rvecs, tvecs;
cv::Mat distCoeffs;
double rtn;
objPtsArr.push_back(objPts);
imgPtsArr.push_back(imgPts);
std::cout << "init Camera" << cameraMatrix << std::endl;
rtn = cv::calibrateCamera(objPtsArr, imgPtsArr, imgSize,
cameraMatrix, distCoeffs, rvecs, tvecs);
std::cout << "final Camera" << cameraMatrix << std::endl;
std::cout << "final rvecs" << rvecs[0] << std::endl;
std::cout << "final tvecs" << tvecs[0] << std::endl;
return rtn;
}

View file

@ -3,27 +3,3 @@ package gocv
// #cgo CXXFLAGS: -std=c++11 // #cgo CXXFLAGS: -std=c++11
// #cgo darwin pkg-config: opencv // #cgo darwin pkg-config: opencv
import "C" import "C"
func NewGcvPoint3f(x, y, z float32) GcvPoint3f_ {
return NewGcvPoint3f_(float32(x), float32(y), float32(z))
}
func NewGcvPoint3d(x, y, z float64) GcvPoint3d_ {
return NewGcvPoint3d_(float64(x), float64(y), float64(z))
}
func NewGcvPoint2f(x, y float32) GcvPoint2f_ {
return NewGcvPoint2f_(float32(x), float32(y))
}
func NewGcvPoint2d(x, y float64) GcvPoint2d_ {
return NewGcvPoint2d_(float64(x), float64(y))
}
func NewGcvSize2f(x, y float32) GcvSize2f_ {
return NewGcvSize2f_(float32(x), float32(y))
}
func NewGcvSize2d(x, y float64) GcvSize2d_ {
return NewGcvSize2d_(float64(x), float64(y))
}

View file

@ -1,11 +0,0 @@
#include <opencv2/opencv.hpp>
#include <vector>
#include <iostream>
typedef std::vector<cv::Point3f> VecPoint3f;
typedef std::vector<cv::Point2f> VecPoint2f;
cv::Mat GcvInitCameraMatrix2D(VecPoint3f objPts, VecPoint2f imgPts);
double GcvCalibrateCamera(VecPoint3f objPts, VecPoint2f imgPts,
cv::Size2i imgSize, cv::Mat cameraMatrix);

View file

@ -1,278 +1,4 @@
%module gocv %module gocv
%include "std_vector.i"
%{ %include "gocv_core.i"
#include "opencv2/core/types_c.h" %include "gocv_calib3d.i"
#include "opencv2/core/version.hpp"
#include "opencv2/core/core.hpp"
#include "gocv.hpp"
%}
%include "gocv.hpp"
/* Classes defined in core.hpp */
namespace cv {
template<typename _Tp> class Size_;
template<typename _Tp> class Point_;
template<typename _Tp> class Rect_;
template<typename _Tp, int cn> class Vec;
//////////////////////////////// Point_ ////////////////////////////////
/*!
template 2D point class.
The class defines a point in 2D space. Data type of the point coordinates is specified
as a template parameter. There are a few shorter aliases available for user convenience.
See cv::Point, cv::Point2i, cv::Point2f and cv::Point2d.
*/
template<typename _Tp> class Point_
{
public:
typedef _Tp value_type;
// various constructors
Point_();
Point_(_Tp _x, _Tp _y);
Point_(const Point_& pt);
Point_(const CvPoint& pt);
Point_(const CvPoint2D32f& pt);
Point_(const Size_<_Tp>& sz);
Point_(const Vec<_Tp, 2>& v);
Point_& operator = (const Point_& pt);
//! conversion to another data type
template<typename _Tp2> operator Point_<_Tp2>() const;
//! conversion to the old-style C structures
operator CvPoint() const;
operator CvPoint2D32f() const;
operator Vec<_Tp, 2>() const;
//! dot product
_Tp dot(const Point_& pt) const;
//! dot product computed in double-precision arithmetics
double ddot(const Point_& pt) const;
//! cross-product
double cross(const Point_& pt) const;
//! checks whether the point is inside the specified rectangle
bool inside(const Rect_<_Tp>& r) const;
_Tp x, y; //< the point coordinates
};
/*!
template 3D point class.
The class defines a point in 3D space. Data type of the point coordinates is specified
as a template parameter.
\see cv::Point3i, cv::Point3f and cv::Point3d
*/
template<typename _Tp> class Point3_
{
public:
typedef _Tp value_type;
// various constructors
Point3_();
Point3_(_Tp _x, _Tp _y, _Tp _z);
Point3_(const Point3_& pt);
explicit Point3_(const Point_<_Tp>& pt);
Point3_(const CvPoint3D32f& pt);
Point3_(const Vec<_Tp, 3>& v);
Point3_& operator = (const Point3_& pt);
//! conversion to another data type
template<typename _Tp2> operator Point3_<_Tp2>() const;
//! conversion to the old-style CvPoint...
operator CvPoint3D32f() const;
//! conversion to cv::Vec<>
operator Vec<_Tp, 3>() const;
//! dot product
_Tp dot(const Point3_& pt) const;
//! dot product computed in double-precision arithmetics
double ddot(const Point3_& pt) const;
//! cross product of the 2 3D points
Point3_ cross(const Point3_& pt) const;
_Tp x, y, z; //< the point coordinates
};
//////////////////////////////// Size_ ////////////////////////////////
/*!
The 2D size class
The class represents the size of a 2D rectangle, image size, matrix size etc.
Normally, cv::Size ~ cv::Size_<int> is used.
*/
template<typename _Tp> class Size_
{
public:
typedef _Tp value_type;
//! various constructors
Size_();
Size_(_Tp _width, _Tp _height);
Size_(const Size_& sz);
Size_(const CvSize& sz);
Size_(const CvSize2D32f& sz);
Size_(const Point_<_Tp>& pt);
Size_& operator = (const Size_& sz);
//! the area (width*height)
_Tp area() const;
//! conversion of another data type.
template<typename _Tp2> operator Size_<_Tp2>() const;
//! conversion to the old-style OpenCV types
operator CvSize() const;
operator CvSize2D32f() const;
_Tp width, height; // the width and the height
};
//////////////////////////////// Rect_ ////////////////////////////////
/*!
The 2D up-right rectangle class
The class represents a 2D rectangle with coordinates of the specified data type.
Normally, cv::Rect ~ cv::Rect_<int> is used.
*/
template<typename _Tp> class Rect_
{
public:
typedef _Tp value_type;
//! various constructors
Rect_();
Rect_(_Tp _x, _Tp _y, _Tp _width, _Tp _height);
Rect_(const Rect_& r);
Rect_(const CvRect& r);
Rect_(const Point_<_Tp>& org, const Size_<_Tp>& sz);
Rect_(const Point_<_Tp>& pt1, const Point_<_Tp>& pt2);
Rect_& operator = ( const Rect_& r );
//! the top-left corner
Point_<_Tp> tl() const;
//! the bottom-right corner
Point_<_Tp> br() const;
//! size (width, height) of the rectangle
Size_<_Tp> size() const;
//! area (width*height) of the rectangle
_Tp area() const;
//! conversion to another data type
template<typename _Tp2> operator Rect_<_Tp2>() const;
//! conversion to the old-style CvRect
operator CvRect() const;
//! checks whether the rectangle contains the point
bool contains(const Point_<_Tp>& pt) const;
_Tp x, y, width, height; //< the top-left corner, as well as width and height of the rectangle
};
%template(GcvSize2i) Size_<int>;
%template(GcvSize2d_) Size_<double>;
%template(GcvSize2f_) Size_<float>;
%template(GcvRect) Rect_<int>;
%template(GcvPoint2i) Point_<int>;
%template(GcvPoint2f_) Point_<float>;
%template(GcvPoint2d_) Point_<double>;
%template(GcvPoint3i) Point3_<int>;
%template(GcvPoint3f_) Point3_<float>;
%template(GcvPoint3d_) Point3_<double>;
/* ----------------- Mat ----------------- */
class Mat
{
public:
//! default constructor
Mat();
//! constructs 2D matrix of the specified size and type
// (_type is CV_8UC1, CV_64FC3, CV_32SC(12) etc.)
Mat(int rows, int cols, int type);
Mat(cv::Size size, int type);
//! constucts 2D matrix and fills it with the specified value _s.
Mat(int rows, int cols, int type, const cv::Scalar& s);
Mat(cv::Size size, int type, const cv::Scalar& s);
//! copy constructor
Mat(const Mat& m);
//! builds matrix from std::vector with or without copying the data
template<typename _Tp> explicit Mat(const vector<_Tp>& vec, bool copyData=false);
//! builds matrix from cv::Vec; the data is copied by default
template<typename _Tp, int n> explicit Mat(const Vec<_Tp, n>& vec, bool copyData=true);
//! builds matrix from cv::Matx; the data is copied by default
template<typename _Tp, int m, int n> explicit Mat(const Matx<_Tp, m, n>& mtx, bool copyData=true);
//! builds matrix from a 2D point
template<typename _Tp> explicit Mat(const Point_<_Tp>& pt, bool copyData=true);
//! builds matrix from a 3D point
template<typename _Tp> explicit Mat(const Point3_<_Tp>& pt, bool copyData=true);
//! destructor - calls release()
~Mat();
//! returns a new matrix header for the specified row
Mat row(int y) const;
//! returns a new matrix header for the specified column
Mat col(int x) const;
//! ... for the specified row span
Mat rowRange(int startrow, int endrow) const;
//! ... for the specified column span
Mat colRange(int startcol, int endcol) const;
//! ... for the specified diagonal
// (d=0 - the main diagonal,
// >0 - a diagonal from the lower half,
// <0 - a diagonal from the upper half)
Mat diag(int d=0) const;
//! constructs a square diagonal matrix which main diagonal is vector "d"
static Mat diag(const Mat& d);
//! returns deep copy of the matrix, i.e. the data is copied
Mat clone() const;
void assignTo( Mat& m, int type=-1 ) const;
//! creates alternative matrix header for the same data, with different
// number of channels and/or different number of rows. see cvReshape.
Mat reshape(int cn, int rows=0) const;
Mat reshape(int cn, int newndims, const int* newsz) const;
//! adds element to the end of 1d matrix (or possibly multiple elements when _Tp=Mat)
template<typename _Tp> void push_back(const _Tp& elem);
template<typename _Tp> void push_back(const Mat_<_Tp>& elem);
void push_back(const Mat& m);
//! removes several hyper-planes from bottom of the matrix
void pop_back(size_t nelems=1);
//! special versions for 2D arrays (especially convenient for referencing image pixels)
template<typename _Tp> _Tp& at(cv::Point pt);
template<typename _Tp> const _Tp& at(cv::Point pt) const;
%template(gcvAtd) at<double>;
%template(gcvAtf) at<float>;
};
}
/* Additional STL types */
namespace std {
%template(GcvPoint3fVector) vector<cv::Point3f>;
%template(GcvPoint2fVector) vector<cv::Point2f>;
%template(GcvIntVector) vector<int>;
%template(GcvFloatVector) vector<float>;
};

56
gocv/gocv_calib3d.cpp Normal file
View file

@ -0,0 +1,56 @@
#include <opencv2/opencv.hpp>
#include <opencv2/core/core.hpp>
#include <iostream>
#include <vector>
#include "gocv_calib3d.hpp"
cv::Mat GcvInitCameraMatrix2D_(VecPoint3f objPts, VecPoint2f imgPts) {
cv::Mat cameraMatrix;
std::vector<VecPoint3f> objPtsArr;
std::vector<VecPoint2f> imgPtsArr;
objPtsArr.push_back(objPts);
imgPtsArr.push_back(imgPts);
cameraMatrix = cv::initCameraMatrix2D(objPtsArr, imgPtsArr, cv::Size(1920, 1080), 1);
return cameraMatrix;
}
double GcvCalibrateCamera_(VecPoint3f objPts, VecPoint2f imgPts,
cv::Size imgSize, cv::Mat& cameraMatrix,
cv::Mat& rvec, cv::Mat& tvec) {
std::vector<VecPoint3f> objPtsArr;
std::vector<VecPoint2f> imgPtsArr;
std::vector<cv::Mat> rvecs, tvecs;
cv::Mat distCoeffs;
double rtn;
objPtsArr.push_back(objPts);
imgPtsArr.push_back(imgPts);
std::cout << "objPts " << std::endl << objPtsArr[0] << std::endl;
std::cout << "imgPts " << std::endl << imgPtsArr[0] << std::endl;
std::cout << "imgSize " << std::endl << imgSize << std::endl;
std::cout << "Before CamMat " << std::endl << cameraMatrix << std::endl;
rtn = cv::calibrateCamera(objPtsArr, imgPtsArr, imgSize,
cameraMatrix, distCoeffs,
rvecs, tvecs, 14575);
rvec = rvecs[0];
tvec = tvecs[0];
std::cout << "After CamMat " << std::endl << cameraMatrix << std::endl;
std::cout << "distCoeffs " << std::endl << distCoeffs << std::endl;
std::cout << "rvec " << std::endl << rvec << std::endl;
std::cout << "tvec " << std::endl << tvec << std::endl;
std::cout << "rms " << std::endl << rtn << std::endl;
return rtn;
}
void GcvRodrigues_(cv::Mat src, cv::Mat& dst) {
cv::Rodrigues(src, dst);
}

113
gocv/gocv_calib3d.go Normal file
View file

@ -0,0 +1,113 @@
package gocv
// #cgo CXXFLAGS: -std=c++11
// #cgo darwin pkg-config: opencv
import "C"
import "github.com/gonum/matrix/mat64"
// GcvInitCameraMatrix2D takes one N-by-3 matrix and one
// N-by-2 Matrix as input.
// Each row in the input matrix represents a point in real
// world (objPts) or in image (imgPts).
// Return: the camera matrix.
func GcvInitCameraMatrix2D(objPts, imgPts *mat64.Dense) (camMat *mat64.Dense) {
nObjPts, objCol := objPts.Dims()
nImgPts, imgCol := imgPts.Dims()
if objCol != 3 || imgCol != 2 || nObjPts != nImgPts {
panic("Invalid dimensions for objPts and imgPts")
}
objPtsVec := NewGcvPoint3f32Vector(int64(nObjPts))
imgPtsVec := NewGcvPoint2f32Vector(int64(nObjPts))
for i := 0; i < nObjPts; i++ {
objPtsVec.Set(i, NewGcvPoint3f32(objPts.Row(nil, i)...))
}
for i := 0; i < nObjPts; i++ {
imgPtsVec.Set(i, NewGcvPoint2f32(imgPts.Row(nil, i)...))
}
camMat = GcvMatToMat64(GcvInitCameraMatrix2D_(objPtsVec, imgPtsVec))
return camMat
}
func GcvCalibrateCamera(objPts, imgPts, camMat *mat64.Dense) (calCamMat, rvec, tvec *mat64.Dense) {
nObjPts, objCol := objPts.Dims()
nImgPts, imgCol := imgPts.Dims()
if objCol != 3 || imgCol != 2 || nObjPts != nImgPts {
panic("Invalid dimensions for objPts and imgPts")
}
objPtsVec := NewGcvPoint3f32Vector(int64(nObjPts))
imgPtsVec := NewGcvPoint2f32Vector(int64(nObjPts))
for i := 0; i < nObjPts; i++ {
objPtsVec.Set(i, NewGcvPoint3f32(objPts.Row(nil, i)...))
}
for i := 0; i < nObjPts; i++ {
imgPtsVec.Set(i, NewGcvPoint2f32(imgPts.Row(nil, i)...))
}
_camMat := Mat64ToGcvMat(camMat)
_rvec := NewGcvMat()
_tvec := NewGcvMat()
_imgSize := NewGcvSize2i(1920, 1080)
GcvCalibrateCamera_(
objPtsVec, imgPtsVec,
_imgSize, _camMat, _rvec, _tvec)
calCamMat = GcvMatToMat64(_camMat)
rvec = GcvMatToMat64(_rvec)
tvec = GcvMatToMat64(_tvec)
return calCamMat, rvec, tvec
}
// Same as cv::Rodrigues
func GcvRodrigues(src *mat64.Dense) (dst *mat64.Dense) {
gcvSrc := Mat64ToGcvMat(src)
gcvDst := NewGcvMat()
GcvRodrigues_(gcvSrc, gcvDst)
dst = GcvMatToMat64(gcvDst)
return dst
}
// func mat64ToGcvPoint3f32Vector(mat *mat64.Dense) NewGcvPoint3f32Vector {
// }
// func TestGcvCalibrateCamera(t *testing.T) {
// objPts := NewGcvPoint3fVector(int64(4))
// objPts.Set(0, NewGcvPoint3f(0, 25, 0))
// objPts.Set(1, NewGcvPoint3f(0, -25, 0))
// objPts.Set(2, NewGcvPoint3f(-47, 25, 0))
// objPts.Set(3, NewGcvPoint3f(-47, -25, 0))
// imgPts := NewGcvPoint2fVector(int64(4))
// imgPts.Set(0, NewGcvPoint2f(1136.4140625, 1041.89208984))
// imgPts.Set(1, NewGcvPoint2f(1845.33190918, 671.39581299))
// imgPts.Set(2, NewGcvPoint2f(302.73373413, 634.79998779))
// imgPts.Set(3, NewGcvPoint2f(1051.46154785, 352.76107788))
// imgSize := NewGcvSize2i(1920, 1080)
// camMat := GcvInitCameraMatrix2D(objPts, imgPts)
// spew.Dump(camMat.GcvAtd(NewGcvSize2i(0, 0)))
// spew.Dump(camMat.GcvAtd(NewGcvSize2i(0, 1)))
// spew.Dump(camMat.GcvAtd(NewGcvSize2i(1, 1)))
// spew.Dump(camMat.GcvAtd(NewGcvSize2i(1, 2)))
// spew.Dump(camMat.GcvAtd(NewGcvSize2i(2, 2)))
// rvec := NewMat()
// tvec := NewMat()
// GcvCalibrateCamera(objPts, imgPts, imgSize, camMat, rvec, tvec)
// MatToMat64(camMat)
// }

14
gocv/gocv_calib3d.hpp Normal file
View file

@ -0,0 +1,14 @@
#include <opencv2/opencv.hpp>
#include <vector>
#include <iostream>
typedef std::vector<cv::Point3f> VecPoint3f;
typedef std::vector<cv::Point2f> VecPoint2f;
cv::Mat GcvInitCameraMatrix2D_(VecPoint3f objPts, VecPoint2f imgPts);
double GcvCalibrateCamera_(VecPoint3f objPts, VecPoint2f imgPts,
cv::Size2i imgSize, cv::Mat& cameraMatrix,
cv::Mat& rvec, cv::Mat& tvec);
void GcvRodrigues_(cv::Mat src, cv::Mat& dst);

5
gocv/gocv_calib3d.i Normal file
View file

@ -0,0 +1,5 @@
%{
#include "gocv_calib3d.hpp"
%}
%include "gocv_calib3d.hpp"

77
gocv/gocv_calib3d_test.go Normal file
View file

@ -0,0 +1,77 @@
package gocv
import (
"testing"
"github.com/gonum/matrix/mat64"
"github.com/stretchr/testify/assert"
)
func TestGcvInitCameraMatrix2D(t *testing.T) {
objPts := mat64.NewDense(4, 3, []float64{
0, 25, 0,
0, -25, 0,
-47, 25, 0,
-47, -25, 0,
})
imgPts := mat64.NewDense(4, 2, []float64{
1136.4140625, 1041.89208984,
1845.33190918, 671.39581299,
302.73373413, 634.79998779,
1051.46154785, 352.76107788,
})
camMat := GcvInitCameraMatrix2D(objPts, imgPts)
assert.Equal(t, camMat.Row(nil, 0), []float64{4828.129063751587, 0, 959.5})
assert.Equal(t, camMat.Row(nil, 1), []float64{0, 4828.129063751587, 539.5})
assert.Equal(t, camMat.Row(nil, 2), []float64{0, 0, 1})
}
func TestGcvCalibrateCamera(t *testing.T) {
objPts := mat64.NewDense(4, 3, []float64{
0, 25, 0,
0, -25, 0,
-47, 25, 0,
-47, -25, 0,
})
imgPts := mat64.NewDense(4, 2, []float64{
1136.4140625, 1041.89208984,
1845.33190918, 671.39581299,
302.73373413, 634.79998779,
1051.46154785, 352.76107788,
})
camMat := GcvInitCameraMatrix2D(objPts, imgPts)
camMat, rvec, tvec := GcvCalibrateCamera(objPts, imgPts, camMat)
assert.Equal(t, camMat.Row(nil, 0), []float64{5.47022369e+03, 0.00000000e+00, 9.59500000e+02})
assert.Equal(t, camMat.Row(nil, 1), []float64{0.00000000e+00, 5.47022369e+03, 5.39500000e+02})
assert.Equal(t, camMat.Row(nil, 2), []float64{0.00000000e+00, 0.00000000e+00, 1.00000000e+00})
assert.Equal(t, rvec.Col(nil, 0), []float64{-0.99458984, 0.54674764, -2.69721055})
assert.Equal(t, tvec.Col(nil, 0), []float64{-23.25417757, -12.6155423, -227.64212085})
}
func TestGcvRodrigues(t *testing.T) {
rvec := mat64.NewDense(3, 1, []float64{
-0.99458984,
0.54674764,
-2.69721055,
})
rmat := GcvRodrigues(rvec)
assert.InDelta(t, rmat.At(0, 0), -0.74853587, 1e-6)
assert.InDelta(t, rmat.At(0, 1), 0.07139127, 1e-6)
assert.InDelta(t, rmat.At(0, 2), 0.65923997, 1e-6)
assert.InDelta(t, rmat.At(1, 0), -0.32247419, 1e-6)
assert.InDelta(t, rmat.At(1, 1), -0.90789575, 1e-6)
assert.InDelta(t, rmat.At(1, 2), -0.26783521, 1e-6)
assert.InDelta(t, rmat.At(2, 0), 0.57940008, 1e-6)
assert.InDelta(t, rmat.At(2, 1), -0.41307214, 1e-6)
assert.InDelta(t, rmat.At(2, 2), 0.70261437, 1e-6)
}

21
gocv/gocv_core.cpp Normal file
View file

@ -0,0 +1,21 @@
#include <opencv2/opencv.hpp>
#include <opencv2/core/core.hpp>
#include <iostream>
#include <vector>
#include "gocv_core.hpp"
cv::Mat Mat64ToGcvMat_(int row, int col, std::vector<double> data) {
assert(row * col == data.size());
cv::Mat mat = cv::Mat(row, col, CV_64F);
for (int i = 0; i < row; ++i) {
for (int j = 0; j < col; ++j) {
mat.at<double>(i, j) = data[i*col + j];
}
}
return mat;
}

84
gocv/gocv_core.go Normal file
View file

@ -0,0 +1,84 @@
package gocv
// #cgo CXXFLAGS: -std=c++11
// #cgo darwin pkg-config: opencv
import "C"
import "github.com/gonum/matrix/mat64"
func NewGcvPoint3f32(pts ...float64) GcvPoint3f32_ {
// This make sure we have default values
safePts := getSafePts(pts, 3)
return NewGcvPoint3f32_(float32(safePts[0]), float32(safePts[1]), float32(safePts[2]))
}
func NewGcvPoint3f64(pts ...float64) GcvPoint3f64_ {
safePts := getSafePts(pts, 3)
return NewGcvPoint3f64_(safePts[0], safePts[1], safePts[2])
}
func NewGcvPoint2f32(pts ...float64) GcvPoint2f32_ {
safePts := getSafePts(pts, 2)
return NewGcvPoint2f32_(float32(safePts[0]), float32(safePts[1]))
}
func NewGcvPoint2f64(pts ...float64) GcvPoint2f64_ {
safePts := getSafePts(pts, 2)
return NewGcvPoint2f64_(safePts[0], safePts[1])
}
func NewGcvSize2f32(pts ...float64) GcvSize2f32_ {
safePts := getSafePts(pts, 2)
return NewGcvSize2f32_(float32(safePts[0]), float32(safePts[1]))
}
func NewGcvSize2f64(pts ...float64) GcvSize2f64_ {
safePts := getSafePts(pts, 2)
return NewGcvSize2f64_(safePts[0], safePts[1])
}
// Convert Mat, which defined by SWIG, to *mat64.Dense.
// The reason is the latter is much easier to handle
// in Go.
// GcvMat is assumed to be 2-dimensional matrix.
func GcvMatToMat64(mat GcvMat) *mat64.Dense {
col := mat.GetCols()
row := mat.GetRows()
data := []float64{}
for i := 0; i < row; i++ {
for j := 0; j < col; j++ {
if fltPtr, ok := mat.GcvAtf64(i, j).(*float64); ok {
data = append(data, *fltPtr)
} else {
panic("Non *float64 passed to MatToMat64")
}
}
}
return mat64.NewDense(row, col, data)
}
// Convert *mat64.Dense to Mat
func Mat64ToGcvMat(mat *mat64.Dense) GcvMat {
row, col := mat.Dims()
rawData := NewGcvFloat64Vector(int64(row * col))
for i := 0; i < row; i++ {
for j := 0; j < col; j++ {
rawData.Set(i*col+j, mat.At(i, j))
}
}
return Mat64ToGcvMat_(row, col, rawData)
}
func getSafePts(pts []float64, size int) []float64 {
// This make sure we have default values
safePts := make([]float64, size, size)
copy(safePts, pts)
return safePts
}

5
gocv/gocv_core.hpp Normal file
View file

@ -0,0 +1,5 @@
#include <opencv2/opencv.hpp>
#include <vector>
#include <iostream>
cv::Mat Mat64ToGcvMat_(int row, int col, std::vector<double> data);

304
gocv/gocv_core.i Normal file
View file

@ -0,0 +1,304 @@
%{
#include "opencv2/core/core.hpp"
#include "gocv_core.hpp"
%}
%include "std_vector.i"
%include "gocv_core.hpp"
/* Classes defined in core.hpp */
namespace cv {
template<typename _Tp> class Size_;
template<typename _Tp> class Point_;
template<typename _Tp> class Rect_;
template<typename _Tp, int cn> class Vec;
//////////////////////////////// Point_ ////////////////////////////////
/*!
template 2D point class.
The class defines a point in 2D space. Data type of the point coordinates is specified
as a template parameter. There are a few shorter aliases available for user convenience.
See cv::Point, cv::Point2i, cv::Point2f and cv::Point2d.
*/
template<typename _Tp> class Point_
{
public:
typedef _Tp value_type;
// various constructors
Point_();
Point_(_Tp _x, _Tp _y);
Point_(const Point_& pt);
Point_(const CvPoint& pt);
Point_(const CvPoint2D32f& pt);
Point_(const Size_<_Tp>& sz);
Point_(const Vec<_Tp, 2>& v);
Point_& operator = (const Point_& pt);
//! conversion to another data type
template<typename _Tp2> operator Point_<_Tp2>() const;
//! conversion to the old-style C structures
operator CvPoint() const;
operator CvPoint2D32f() const;
operator Vec<_Tp, 2>() const;
//! dot product
_Tp dot(const Point_& pt) const;
//! dot product computed in double-precision arithmetics
double ddot(const Point_& pt) const;
//! cross-product
double cross(const Point_& pt) const;
//! checks whether the point is inside the specified rectangle
bool inside(const Rect_<_Tp>& r) const;
_Tp x, y; //< the point coordinates
};
/*!
template 3D point class.
The class defines a point in 3D space. Data type of the point coordinates is specified
as a template parameter.
\see cv::Point3i, cv::Point3f and cv::Point3d
*/
template<typename _Tp> class Point3_
{
public:
typedef _Tp value_type;
// various constructors
Point3_();
Point3_(_Tp _x, _Tp _y, _Tp _z);
Point3_(const Point3_& pt);
explicit Point3_(const Point_<_Tp>& pt);
Point3_(const CvPoint3D32f& pt);
Point3_(const Vec<_Tp, 3>& v);
Point3_& operator = (const Point3_& pt);
//! conversion to another data type
template<typename _Tp2> operator Point3_<_Tp2>() const;
//! conversion to the old-style CvPoint...
operator CvPoint3D32f() const;
//! conversion to cv::Vec<>
operator Vec<_Tp, 3>() const;
//! dot product
_Tp dot(const Point3_& pt) const;
//! dot product computed in double-precision arithmetics
double ddot(const Point3_& pt) const;
//! cross product of the 2 3D points
Point3_ cross(const Point3_& pt) const;
_Tp x, y, z; //< the point coordinates
};
//////////////////////////////// Size_ ////////////////////////////////
/*!
The 2D size class
The class represents the size of a 2D rectangle, image size, matrix size etc.
Normally, cv::Size ~ cv::Size_<int> is used.
*/
template<typename _Tp> class Size_
{
public:
typedef _Tp value_type;
//! various constructors
Size_();
Size_(_Tp _width, _Tp _height);
Size_(const Size_& sz);
Size_(const CvSize& sz);
Size_(const CvSize2D32f& sz);
Size_(const Point_<_Tp>& pt);
Size_& operator = (const Size_& sz);
//! the area (width*height)
_Tp area() const;
//! conversion of another data type.
template<typename _Tp2> operator Size_<_Tp2>() const;
//! conversion to the old-style OpenCV types
operator CvSize() const;
operator CvSize2D32f() const;
_Tp width, height; // the width and the height
};
//////////////////////////////// Rect_ ////////////////////////////////
/*!
The 2D up-right rectangle class
The class represents a 2D rectangle with coordinates of the specified data type.
Normally, cv::Rect ~ cv::Rect_<int> is used.
*/
template<typename _Tp> class Rect_
{
public:
typedef _Tp value_type;
//! various constructors
Rect_();
Rect_(_Tp _x, _Tp _y, _Tp _width, _Tp _height);
Rect_(const Rect_& r);
Rect_(const CvRect& r);
Rect_(const Point_<_Tp>& org, const Size_<_Tp>& sz);
Rect_(const Point_<_Tp>& pt1, const Point_<_Tp>& pt2);
Rect_& operator = ( const Rect_& r );
//! the top-left corner
Point_<_Tp> tl() const;
//! the bottom-right corner
Point_<_Tp> br() const;
//! size (width, height) of the rectangle
Size_<_Tp> size() const;
//! area (width*height) of the rectangle
_Tp area() const;
//! conversion to another data type
template<typename _Tp2> operator Rect_<_Tp2>() const;
//! conversion to the old-style CvRect
operator CvRect() const;
//! checks whether the rectangle contains the point
bool contains(const Point_<_Tp>& pt) const;
_Tp x, y, width, height; //< the top-left corner, as well as width and height of the rectangle
};
%template(GcvSize2i) Size_<int>;
%template(GcvSize2f32_) Size_<float>;
%template(GcvSize2f64_) Size_<double>;
%template(GcvRect) Rect_<int>;
%template(GcvPoint2i) Point_<int>;
%template(GcvPoint2f32_) Point_<float>;
%template(GcvPoint2f64_) Point_<double>;
%template(GcvPoint3i) Point3_<int>;
%template(GcvPoint3f32_) Point3_<float>;
%template(GcvPoint3f64_) Point3_<double>;
/* ----------------- Mat ----------------- */
%rename(GcvMat) Mat;
class Mat
{
public:
//! default constructor
Mat();
//! constructs 2D matrix of the specified size and type
// (_type is CV_8UC1, CV_64FC3, CV_32SC(12) etc.)
Mat(int rows, int cols, int type);
Mat(cv::Size size, int type);
//! constucts 2D matrix and fills it with the specified value _s.
Mat(int rows, int cols, int type, const cv::Scalar& s);
Mat(cv::Size size, int type, const cv::Scalar& s);
//! copy constructor
Mat(const Mat& m);
//! builds matrix from std::vector with or without copying the data
template<typename _Tp> explicit Mat(const vector<_Tp>& vec, bool copyData=false);
//! builds matrix from cv::Vec; the data is copied by default
template<typename _Tp, int n> explicit Mat(const Vec<_Tp, n>& vec, bool copyData=true);
//! builds matrix from cv::Matx; the data is copied by default
template<typename _Tp, int m, int n> explicit Mat(const Matx<_Tp, m, n>& mtx, bool copyData=true);
//! builds matrix from a 2D point
template<typename _Tp> explicit Mat(const Point_<_Tp>& pt, bool copyData=true);
//! builds matrix from a 3D point
template<typename _Tp> explicit Mat(const Point3_<_Tp>& pt, bool copyData=true);
//! destructor - calls release()
~Mat();
//! returns a new matrix header for the specified row
Mat row(int y) const;
//! returns a new matrix header for the specified column
Mat col(int x) const;
//! ... for the specified row span
Mat rowRange(int startrow, int endrow) const;
//! ... for the specified column span
Mat colRange(int startcol, int endcol) const;
//! ... for the specified diagonal
// (d=0 - the main diagonal,
// >0 - a diagonal from the lower half,
// <0 - a diagonal from the upper half)
Mat diag(int d=0) const;
//! constructs a square diagonal matrix which main diagonal is vector "d"
static Mat diag(const Mat& d);
//! returns deep copy of the matrix, i.e. the data is copied
Mat clone() const;
void assignTo( Mat& m, int type=-1 ) const;
//! creates alternative matrix header for the same data, with different
// number of channels and/or different number of rows. see cvReshape.
Mat reshape(int cn, int rows=0) const;
Mat reshape(int cn, int newndims, const int* newsz) const;
//! adds element to the end of 1d matrix (or possibly multiple elements when _Tp=Mat)
template<typename _Tp> void push_back(const _Tp& elem);
template<typename _Tp> void push_back(const Mat_<_Tp>& elem);
void push_back(const Mat& m);
//! removes several hyper-planes from bottom of the matrix
void pop_back(size_t nelems=1);
//! special versions for 2D arrays (especially convenient for referencing image pixels)
template<typename _Tp> _Tp& at(int i0=0);
template<typename _Tp> const _Tp& at(int i0=0) const;
template<typename _Tp> _Tp& at(int i0, int i1);
template<typename _Tp> const _Tp& at(int i0, int i1) const;
template<typename _Tp> _Tp& at(int i0, int i1, int i2);
template<typename _Tp> const _Tp& at(int i0, int i1, int i2) const;
template<typename _Tp> _Tp& at(const int* idx);
template<typename _Tp> const _Tp& at(const int* idx) const;
template<typename _Tp, int n> _Tp& at(const Vec<int, n>& idx);
template<typename _Tp, int n> const _Tp& at(const Vec<int, n>& idx) const;
template<typename _Tp> _Tp& at(cv::Point pt);
template<typename _Tp> const _Tp& at(cv::Point pt) const;
%template(gcvAtf32) at<float>;
%template(gcvAtf64) at<double>;
/*! includes several bit-fields:
- the magic signature
- continuity flag
- depth
- number of channels
*/
int flags;
//! the matrix dimensionality, >= 2
int dims;
//! the number of rows and columns or (-1, -1) when the matrix has more than 2 dimensions
int rows, cols;
};
}
/* Additional STL types */
namespace std {
%template(GcvPoint3f32Vector) vector<cv::Point3f>;
%template(GcvPoint2f32Vector) vector<cv::Point2f>;
%template(GcvIntVector) vector<int>;
%template(GcvFloat32Vector) vector<float>;
%template(GcvFloat64Vector) vector<double>;
};

38
gocv/gocv_core_test.go Normal file
View file

@ -0,0 +1,38 @@
package gocv
import (
"testing"
"github.com/davecgh/go-spew/spew"
"github.com/gonum/matrix/mat64"
)
func TestNewGcvPoint3f32(t *testing.T) {
pt := NewGcvPoint3f32(3, 1)
spew.Dump(pt)
}
func TestNewGcvPoint2f32(t *testing.T) {
pt := NewGcvPoint2f32(3, 1)
spew.Dump(pt)
}
func TestNewGcvSize2f64(t *testing.T) {
size := NewGcvSize2f64(3, 1)
spew.Dump(size)
}
func TestMat(t *testing.T) {
mat := NewGcvMat()
mat2 := NewGcvMat(mat)
spew.Dump(mat2)
}
func TestMat64ToGcvMat(t *testing.T) {
mat := mat64.NewDense(3, 2, []float64{
0, 1,
1.23, 4,
-12.3, -4,
})
spew.Dump(Mat64ToGcvMat(mat))
}

View file

@ -1,69 +0,0 @@
package gocv
import (
"testing"
"github.com/davecgh/go-spew/spew"
)
func TestNewGcvPoint3f(t *testing.T) {
pt := NewGcvPoint3f(3, 1, 2)
spew.Dump(pt)
}
func TestNewGcvPoint2f(t *testing.T) {
pt := NewGcvPoint2f(3, 1)
spew.Dump(pt)
}
func TestNewGcvSize2d(t *testing.T) {
size := NewGcvSize2d(3, 1)
spew.Dump(size)
}
func TestMat(t *testing.T) {
mat := NewMat()
mat2 := NewMat(mat)
spew.Dump(mat2)
}
func TestGcvInitCameraMatrix2D(t *testing.T) {
objPts := NewGcvPoint3fVector(int64(4))
objPts.Set(0, NewGcvPoint3f(0, 25, 0))
objPts.Set(1, NewGcvPoint3f(0, -25, 0))
objPts.Set(2, NewGcvPoint3f(-47, 25, 0))
objPts.Set(3, NewGcvPoint3f(-47, -25, 0))
imgPts := NewGcvPoint2fVector(int64(4))
imgPts.Set(0, NewGcvPoint2f(1136.4140625, 1041.89208984))
imgPts.Set(1, NewGcvPoint2f(1845.33190918, 671.39581299))
imgPts.Set(2, NewGcvPoint2f(302.73373413, 634.79998779))
imgPts.Set(3, NewGcvPoint2f(1051.46154785, 352.76107788))
camMat := GcvInitCameraMatrix2D(objPts, imgPts)
spew.Dump(camMat.GcvAtd(NewGcvSize2i(0, 0)))
spew.Dump(camMat.GcvAtd(NewGcvSize2i(0, 1)))
spew.Dump(camMat.GcvAtd(NewGcvSize2i(1, 1)))
spew.Dump(camMat.GcvAtd(NewGcvSize2i(1, 2)))
spew.Dump(camMat.GcvAtd(NewGcvSize2i(2, 2)))
}
func TestGcvCalibrateCamera(t *testing.T) {
objPts := NewGcvPoint3fVector(int64(4))
objPts.Set(0, NewGcvPoint3f(0, 25, 0))
objPts.Set(1, NewGcvPoint3f(0, -25, 0))
objPts.Set(2, NewGcvPoint3f(-47, 25, 0))
objPts.Set(3, NewGcvPoint3f(-47, -25, 0))
imgPts := NewGcvPoint2fVector(int64(4))
imgPts.Set(0, NewGcvPoint2f(1136.4140625, 1041.89208984))
imgPts.Set(1, NewGcvPoint2f(1845.33190918, 671.39581299))
imgPts.Set(2, NewGcvPoint2f(302.73373413, 634.79998779))
imgPts.Set(3, NewGcvPoint2f(1051.46154785, 352.76107788))
imgSize := NewGcvSize2i(1920, 1080)
camMat := GcvInitCameraMatrix2D(objPts, imgPts)
GcvCalibrateCamera(objPts, imgPts, imgSize, camMat)
}