Compare commits

...
Sign in to create a new pull request.

34 commits
cv2 ... master

Author SHA1 Message Date
Chih-Wei (Bert) Chang
1d8dd6c04e Merge pull request #65 from deltamobile/updated_gonum_matrix
Updated gonum matrix
2016-01-27 00:08:56 +08:00
James Graves
85bef28375 Remove erroneous ColView() calls.
Commit 9360634c0c inserted calls
to ColView() when not needed, causing out-of-bounds errors.
This fixes the unit tests.
2016-01-26 10:00:06 -06:00
James Graves
eb896f771a Fixed usage of TCopy() and Row() Col().
API for gonum/matrix has changed.
TCopy() has been removed, use Clone() after T().
Row() and Col() are no longer methods of dense matrix, but
regular module functions now.
2016-01-26 09:56:45 -06:00
Chih-Wei (Bert) Chang
63c522d448 Merge pull request #63 from 9nut/master
Added a sample for face detection on video from webcam
2016-01-17 09:36:11 +08:00
Skip Tavakkolian
033205d5e7 Added a sample for face detection on video from builtin camera 2016-01-07 10:59:43 -08:00
Chih-Wei (Bert) Chang
60747d253e Merge pull request #61 from hpgood/patch-1
update the api of "github.com/gonum/matrix/mat64"
2015-11-06 21:47:26 +08:00
hpgood
9360634c0c update the api of "github.com/gonum/matrix/mat64"
*mat64.Dense has removed the "Col" function.
2015-11-03 13:34:14 +08:00
Chih-Wei (Bert) Chang
08a8c82102 Merge pull request #56 from davidoram/feature/sequence-traversal
Feature/sequence traversal
2015-09-19 08:29:16 +08:00
David Oram
857725be79 Added sequence, curve and contour related functions 2015-09-14 17:21:21 +12:00
David Oram
17d76c68f9 Merge branch 'master' of https://github.com/lazywei/go-opencv 2015-09-11 06:19:43 +12:00
Chih-Wei (Bert) Chang
b115d87f0d Merge pull request #55 from davidoram/feature/fix-eqialize-hist
Feature/fix eqialize hist
2015-09-10 19:19:18 +08:00
David Oram
895f618849 removed unused pic 2015-09-10 17:29:16 +12:00
David Oram
2417f71bcb Removed duplicate EqualizeHist function 2015-09-10 17:27:25 +12:00
Chih-Wei (Bert) Chang
73ab0e8b58 Merge pull request #54 from davidoram/feature/contours
Feature/contours
2015-09-10 13:01:15 +08:00
David Oram
f812503e45 Refactored FindCountours to pass all parameters needed 2015-09-10 16:56:27 +12:00
David Oram
02da2d4700 Added functions:
- FindContours
- DrawContours
- Set
- EqualizeHist

and associated constants
2015-09-10 16:51:38 +12:00
Chih-Wei (Bert) Chang
d59c967c2c Merge pull request #53 from davidoram/feature/average
Feature/average
2015-09-05 11:32:39 +08:00
David Oram
8f000e16ff Created basic functionality 2015-09-01 06:29:03 +12:00
Dave Oram
94deb59c3d Merge pull request #2 from davidoram/feature/average
Feature/average
2015-08-29 16:57:05 +12:00
David Oram
b7bb2a16d7 Added missing smoothing type constants 2015-08-29 16:30:39 +12:00
David Oram
3014fc92fb Added 'EqualizeHist' function 2015-08-29 16:29:51 +12:00
David Oram
0918c9eef3 Added 'Avg' function 2015-08-29 14:40:11 +12:00
Chih-Wei (Bert) Chang
19f0ae0cba Merge pull request #52 from davidoram/feature/puttext
Added support for putText
2015-08-15 14:20:05 +08:00
Dave Oram
aa77750ab9 Merge pull request #1 from davidoram/feature/puttext
Added support for putText
2015-08-15 14:41:35 +12:00
David Oram
12b9646b8b Added support for putText 2015-08-15 12:05:47 +12:00
Chih-Wei Chang
e404f82893 Godep is not supposed to used in package. 2015-07-02 20:50:03 +08:00
Chih-Wei Chang
2a172b0a22 Add opencv flag for linux. 2015-06-21 13:53:39 -07:00
Chih-Wei Chang
40ed44c20c Complete initCameraMatrix2D, calibrateCamera interface. 2015-02-23 17:56:59 +08:00
Chih-Wei Chang
2afcd2a05b Takes column vector instead. 2015-02-23 17:46:13 +08:00
Chih-Wei Chang
7fdd343dbf Merge branch 'cv2' 2015-02-18 15:08:00 +08:00
Chih-Wei Chang
4a10d69aa0 Try to use Godep to handle dependencies. 2015-02-18 14:42:46 +08:00
Chih-Wei Chang
27d60c564a Merge pull request #46 from lazywei/cv2
[WIP] Further wrapping based on mat64
2015-02-17 12:42:47 +08:00
Chih-Wei Chang
9573d42acc Merge pull request #45 from lazywei/cv2
[WIP Wrap basic types.
2015-02-16 12:51:44 +08:00
Chih-Wei Chang
119a8baae1 Merge pull request #44 from lazywei/cv2
Wrap OpenCV2's Calib3d module with SWIG
2015-02-15 14:20:40 +08:00
15 changed files with 433 additions and 86 deletions

View file

@ -2,4 +2,5 @@ package gocv
// #cgo CXXFLAGS: -std=c++11 // #cgo CXXFLAGS: -std=c++11
// #cgo darwin pkg-config: opencv // #cgo darwin pkg-config: opencv
// #cgo linux pkg-config: opencv
import "C" import "C"

View file

@ -5,7 +5,7 @@
#include "gocv_calib3d.hpp" #include "gocv_calib3d.hpp"
cv::Mat GcvInitCameraMatrix2D_(VecPoint3f objPts, VecPoint2f imgPts) { cv::Mat GcvInitCameraMatrix2D_(VecPoint3f objPts, VecPoint2f imgPts, cv::Size imgSize, double aspectRatio) {
cv::Mat cameraMatrix; cv::Mat cameraMatrix;
std::vector<VecPoint3f> objPtsArr; std::vector<VecPoint3f> objPtsArr;
@ -14,17 +14,16 @@ cv::Mat GcvInitCameraMatrix2D_(VecPoint3f objPts, VecPoint2f imgPts) {
objPtsArr.push_back(objPts); objPtsArr.push_back(objPts);
imgPtsArr.push_back(imgPts); imgPtsArr.push_back(imgPts);
cameraMatrix = cv::initCameraMatrix2D(objPtsArr, imgPtsArr, cv::Size(1920, 1080), 1); cameraMatrix = cv::initCameraMatrix2D(objPtsArr, imgPtsArr, imgSize, aspectRatio);
return cameraMatrix; return cameraMatrix;
} }
double GcvCalibrateCamera_(VecPoint3f objPts, VecPoint2f imgPts, double GcvCalibrateCamera_(VecPoint3f objPts, VecPoint2f imgPts,
cv::Size imgSize, cv::Mat& cameraMatrix, cv::Size imgSize, cv::Mat& cameraMatrix, cv::Mat distCoeffs,
cv::Mat& rvec, cv::Mat& tvec) { cv::Mat& rvec, cv::Mat& tvec, int flags) {
std::vector<VecPoint3f> objPtsArr; std::vector<VecPoint3f> objPtsArr;
std::vector<VecPoint2f> imgPtsArr; std::vector<VecPoint2f> imgPtsArr;
std::vector<cv::Mat> rvecs, tvecs; std::vector<cv::Mat> rvecs, tvecs;
cv::Mat distCoeffs;
double rtn; double rtn;
objPtsArr.push_back(objPts); objPtsArr.push_back(objPts);
@ -37,7 +36,7 @@ double GcvCalibrateCamera_(VecPoint3f objPts, VecPoint2f imgPts,
rtn = cv::calibrateCamera(objPtsArr, imgPtsArr, imgSize, rtn = cv::calibrateCamera(objPtsArr, imgPtsArr, imgSize,
cameraMatrix, distCoeffs, cameraMatrix, distCoeffs,
rvecs, tvecs, 14575); rvecs, tvecs, flags);
rvec = rvecs[0]; rvec = rvecs[0];
tvec = tvecs[0]; tvec = tvecs[0];

View file

@ -2,64 +2,73 @@ package gocv
// #cgo CXXFLAGS: -std=c++11 // #cgo CXXFLAGS: -std=c++11
// #cgo darwin pkg-config: opencv // #cgo darwin pkg-config: opencv
// #cgo linux pkg-config: opencv
import "C" import "C"
import "github.com/gonum/matrix/mat64" import "github.com/gonum/matrix/mat64"
// GcvInitCameraMatrix2D takes one N-by-3 matrix and one // GcvInitCameraMatrix2D takes one 3-by-N matrix and one 2-by-N Matrix as input.
// N-by-2 Matrix as input. // Each column in the input matrix represents a point in real world (objPts) or
// Each row in the input matrix represents a point in real // in image (imgPts).
// world (objPts) or in image (imgPts).
// Return: the camera matrix. // Return: the camera matrix.
func GcvInitCameraMatrix2D(objPts, imgPts *mat64.Dense) (camMat *mat64.Dense) { func GcvInitCameraMatrix2D(objPts, imgPts *mat64.Dense, dims [2]int,
nObjPts, objCol := objPts.Dims() aspectRatio float64) (camMat *mat64.Dense) {
nImgPts, imgCol := imgPts.Dims()
if objCol != 3 || imgCol != 2 || nObjPts != nImgPts { objDim, nObjPts := objPts.Dims()
imgDim, nImgPts := imgPts.Dims()
if objDim != 3 || imgDim != 2 || nObjPts != nImgPts {
panic("Invalid dimensions for objPts and imgPts") panic("Invalid dimensions for objPts and imgPts")
} }
objPtsVec := NewGcvPoint3f32Vector(int64(nObjPts)) objPtsVec := NewGcvPoint3f32Vector(int64(nObjPts))
imgPtsVec := NewGcvPoint2f32Vector(int64(nObjPts)) imgPtsVec := NewGcvPoint2f32Vector(int64(nObjPts))
for i := 0; i < nObjPts; i++ { for j := 0; j < nObjPts; j++ {
objPtsVec.Set(i, NewGcvPoint3f32(objPts.Row(nil, i)...)) objPtsVec.Set(j, NewGcvPoint3f32(mat64.Col(nil, j, objPts)...))
} }
for i := 0; i < nObjPts; i++ { for j := 0; j < nObjPts; j++ {
imgPtsVec.Set(i, NewGcvPoint2f32(imgPts.Row(nil, i)...)) imgPtsVec.Set(j, NewGcvPoint2f32(mat64.Col(nil, j, imgPts)...))
} }
camMat = GcvMatToMat64(GcvInitCameraMatrix2D_(objPtsVec, imgPtsVec)) _imgSize := NewGcvSize2i(dims[0], dims[1])
camMat = GcvMatToMat64(GcvInitCameraMatrix2D_(
objPtsVec, imgPtsVec, _imgSize, aspectRatio))
return camMat return camMat
} }
func GcvCalibrateCamera(objPts, imgPts, camMat *mat64.Dense) (calCamMat, rvec, tvec *mat64.Dense) { func GcvCalibrateCamera(objPts, imgPts, camMat, distCoeffs *mat64.Dense,
nObjPts, objCol := objPts.Dims() dims [2]int, flags int) (calCamMat, rvec, tvec *mat64.Dense) {
nImgPts, imgCol := imgPts.Dims()
if objCol != 3 || imgCol != 2 || nObjPts != nImgPts { objDim, nObjPts := objPts.Dims()
imgDim, nImgPts := imgPts.Dims()
if objDim != 3 || imgDim != 2 || nObjPts != nImgPts {
panic("Invalid dimensions for objPts and imgPts") panic("Invalid dimensions for objPts and imgPts")
} }
objPtsVec := NewGcvPoint3f32Vector(int64(nObjPts)) objPtsVec := NewGcvPoint3f32Vector(int64(nObjPts))
imgPtsVec := NewGcvPoint2f32Vector(int64(nObjPts)) imgPtsVec := NewGcvPoint2f32Vector(int64(nObjPts))
for i := 0; i < nObjPts; i++ { for j := 0; j < nObjPts; j++ {
objPtsVec.Set(i, NewGcvPoint3f32(objPts.Row(nil, i)...)) objPtsVec.Set(j, NewGcvPoint3f32(mat64.Col(nil, j, objPts)...))
} }
for i := 0; i < nObjPts; i++ { for j := 0; j < nObjPts; j++ {
imgPtsVec.Set(i, NewGcvPoint2f32(imgPts.Row(nil, i)...)) imgPtsVec.Set(j, NewGcvPoint2f32(mat64.Col(nil, j, imgPts)...))
} }
_camMat := Mat64ToGcvMat(camMat) _camMat := Mat64ToGcvMat(camMat)
_distCoeffs := Mat64ToGcvMat(distCoeffs)
_rvec := NewGcvMat() _rvec := NewGcvMat()
_tvec := NewGcvMat() _tvec := NewGcvMat()
_imgSize := NewGcvSize2i(1920, 1080) _imgSize := NewGcvSize2i(dims[0], dims[1])
GcvCalibrateCamera_( GcvCalibrateCamera_(
objPtsVec, imgPtsVec, objPtsVec, imgPtsVec,
_imgSize, _camMat, _rvec, _tvec) _imgSize, _camMat, _distCoeffs,
_rvec, _tvec, flags)
calCamMat = GcvMatToMat64(_camMat) calCamMat = GcvMatToMat64(_camMat)
rvec = GcvMatToMat64(_rvec) rvec = GcvMatToMat64(_rvec)
@ -68,7 +77,7 @@ func GcvCalibrateCamera(objPts, imgPts, camMat *mat64.Dense) (calCamMat, rvec, t
return calCamMat, rvec, tvec return calCamMat, rvec, tvec
} }
// Same as cv::Rodrigues // GcvRodrigues takes a 3D column vector, and apply cv::Rodrigues to it.
func GcvRodrigues(src *mat64.Dense) (dst *mat64.Dense) { func GcvRodrigues(src *mat64.Dense) (dst *mat64.Dense) {
gcvSrc := Mat64ToGcvMat(src) gcvSrc := Mat64ToGcvMat(src)
gcvDst := NewGcvMat() gcvDst := NewGcvMat()
@ -77,37 +86,3 @@ func GcvRodrigues(src *mat64.Dense) (dst *mat64.Dense) {
return dst 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)
// }

View file

@ -5,10 +5,11 @@
typedef std::vector<cv::Point3f> VecPoint3f; typedef std::vector<cv::Point3f> VecPoint3f;
typedef std::vector<cv::Point2f> VecPoint2f; typedef std::vector<cv::Point2f> VecPoint2f;
cv::Mat GcvInitCameraMatrix2D_(VecPoint3f objPts, VecPoint2f imgPts); cv::Mat GcvInitCameraMatrix2D_(VecPoint3f objPts, VecPoint2f imgPts,
cv::Size imgSize, double aspectRatio);
double GcvCalibrateCamera_(VecPoint3f objPts, VecPoint2f imgPts, double GcvCalibrateCamera_(VecPoint3f objPts, VecPoint2f imgPts,
cv::Size2i imgSize, cv::Mat& cameraMatrix, cv::Size imgSize, cv::Mat& cameraMatrix, cv::Mat distCoeffs,
cv::Mat& rvec, cv::Mat& tvec); cv::Mat& rvec, cv::Mat& tvec, int flags);
void GcvRodrigues_(cv::Mat src, cv::Mat& dst); void GcvRodrigues_(cv::Mat src, cv::Mat& dst);

View file

@ -24,6 +24,7 @@ func TestGcvInitCameraMatrix2D(t *testing.T) {
-0.226950, 0.942377, -0.899869, -0.226950, 0.942377, -0.899869,
-1.148912, 0.093725, 0.634745, -1.148912, 0.093725, 0.634745,
}) })
objPts.Clone(objPts.T())
imgPts := mat64.NewDense(10, 2, []float64{ imgPts := mat64.NewDense(10, 2, []float64{
-0.384281, -0.299055, -0.384281, -0.299055,
@ -37,14 +38,15 @@ func TestGcvInitCameraMatrix2D(t *testing.T) {
0.631444, -0.340257, 0.631444, -0.340257,
-0.647580, 0.502113, -0.647580, 0.502113,
}) })
imgPts.Clone(imgPts.T())
camMat := GcvInitCameraMatrix2D(objPts, imgPts) camMat := GcvInitCameraMatrix2D(objPts, imgPts, [2]int{1920, 1080}, 1)
assert.InDeltaSlice(t, []float64{1.47219772e+03, 0.00000000e+00, 9.59500000e+02}, assert.InDeltaSlice(t, []float64{1.47219772e+03, 0.00000000e+00, 9.59500000e+02},
camMat.Row(nil, 0), DELTA) mat64.Row(nil, 0, camMat), DELTA)
assert.InDeltaSlice(t, []float64{0.00000000e+00, 1.47219772e+03, 5.39500000e+02}, assert.InDeltaSlice(t, []float64{0.00000000e+00, 1.47219772e+03, 5.39500000e+02},
camMat.Row(nil, 1), DELTA) mat64.Row(nil, 1, camMat), DELTA)
assert.InDeltaSlice(t, []float64{0.00000000e+00, 0.00000000e+00, 1.00000000e+00}, assert.InDeltaSlice(t, []float64{0.00000000e+00, 0.00000000e+00, 1.00000000e+00},
camMat.Row(nil, 2), DELTA) mat64.Row(nil, 2, camMat), DELTA)
} }
func TestGcvCalibrateCamera(t *testing.T) { func TestGcvCalibrateCamera(t *testing.T) {
@ -60,6 +62,7 @@ func TestGcvCalibrateCamera(t *testing.T) {
-0.226950, 0.942377, -0.899869, -0.226950, 0.942377, -0.899869,
-1.148912, 0.093725, 0.634745, -1.148912, 0.093725, 0.634745,
}) })
objPts.Clone(objPts.T())
imgPts := mat64.NewDense(10, 2, []float64{ imgPts := mat64.NewDense(10, 2, []float64{
-0.384281, -0.299055, -0.384281, -0.299055,
@ -73,22 +76,21 @@ func TestGcvCalibrateCamera(t *testing.T) {
0.631444, -0.340257, 0.631444, -0.340257,
-0.647580, 0.502113, -0.647580, 0.502113,
}) })
imgPts.Clone(imgPts.T())
camMat := GcvInitCameraMatrix2D(objPts, imgPts) camMat := GcvInitCameraMatrix2D(objPts, imgPts, [2]int{1920, 1080}, 1)
camMat, rvec, tvec := GcvCalibrateCamera(objPts, imgPts, camMat) distCoeffs := mat64.NewDense(5, 1, []float64{0, 0, 0, 0, 0})
// stackedMat := *mat64.NewDense(0, 0, nil) camMat, rvec, tvec := GcvCalibrateCamera(
// stackedMat.Augment(GcvRodrigues(rvec), tvec) objPts, imgPts, camMat, distCoeffs, [2]int{1920, 1080}, 14575)
// camMat.Mul(camMat, &stackedMat) assert.InDeltaSlice(t, []float64{-46.15296606, 0., 959.5}, mat64.Row(nil, 0, camMat), DELTA)
assert.InDeltaSlice(t, []float64{0., -46.15296606, 539.5}, mat64.Row(nil, 1, camMat), DELTA)
assert.InDeltaSlice(t, []float64{0., 0., 1.}, mat64.Row(nil, 2, camMat), DELTA)
assert.InDeltaSlice(t, []float64{-46.15296606, 0., 959.5}, camMat.Row(nil, 0), DELTA) assert.InDeltaSlice(t, []float64{-0.98405029, -0.93443411, -0.26304667}, mat64.Col(nil, 0, rvec), DELTA)
assert.InDeltaSlice(t, []float64{0., -46.15296606, 539.5}, camMat.Row(nil, 1), DELTA) assert.InDeltaSlice(t, []float64{0.6804739, 0.47530207, -0.04833094}, mat64.Col(nil, 0, tvec), DELTA)
assert.InDeltaSlice(t, []float64{0., 0., 1.}, camMat.Row(nil, 2), DELTA)
assert.InDeltaSlice(t, []float64{-0.98405029, -0.93443411, -0.26304667}, rvec.Col(nil, 0), DELTA)
assert.InDeltaSlice(t, []float64{0.6804739, 0.47530207, -0.04833094}, tvec.Col(nil, 0), DELTA)
} }
func TestGcvRodrigues(t *testing.T) { func TestGcvRodrigues(t *testing.T) {
@ -99,7 +101,7 @@ func TestGcvRodrigues(t *testing.T) {
}) })
rmat := GcvRodrigues(rvec) rmat := GcvRodrigues(rvec)
assert.InDeltaSlice(t, []float64{0.59922526, 0.57799222, -0.55394411}, rmat.Row(nil, 0), DELTA) assert.InDeltaSlice(t, []float64{0.59922526, 0.57799222, -0.55394411}, mat64.Row(nil, 0, rmat), DELTA)
assert.InDeltaSlice(t, []float64{0.20413818, 0.558743, 0.80382452}, rmat.Row(nil, 1), DELTA) assert.InDeltaSlice(t, []float64{0.20413818, 0.558743, 0.80382452}, mat64.Row(nil, 1, rmat), DELTA)
assert.InDeltaSlice(t, []float64{0.77411672, -0.5947531, 0.21682264}, rmat.Row(nil, 2), DELTA) assert.InDeltaSlice(t, []float64{0.77411672, -0.5947531, 0.21682264}, mat64.Row(nil, 2, rmat), DELTA)
} }

View file

@ -2,6 +2,7 @@ package gocv
// #cgo CXXFLAGS: -std=c++11 // #cgo CXXFLAGS: -std=c++11
// #cgo darwin pkg-config: opencv // #cgo darwin pkg-config: opencv
// #cgo linux pkg-config: opencv
import "C" import "C"
import "github.com/gonum/matrix/mat64" import "github.com/gonum/matrix/mat64"

BIN
images/lena_with_text.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 KiB

BIN
images/pic5_contours.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

View file

@ -23,7 +23,11 @@ const (
CV_BGR2BGRA = C.CV_BGR2BGRA CV_BGR2BGRA = C.CV_BGR2BGRA
CV_RGBA2BGRA = C.CV_RGBA2BGRA CV_RGBA2BGRA = C.CV_RGBA2BGRA
CV_BLUR = C.CV_BLUR CV_BLUR_NO_SCALE = C.CV_BLUR_NO_SCALE
CV_BLUR = C.CV_BLUR
CV_GAUSSIAN = C.CV_GAUSSIAN
CV_MEDIAN = C.CV_MEDIAN
CV_BILATERAL = C.CV_BILATERAL
CV_8U = C.CV_8U CV_8U = C.CV_8U
CV_8S = C.CV_8S CV_8S = C.CV_8S

View file

@ -142,6 +142,11 @@ func (img *IplImage) Get3D(x, y, z int) Scalar {
return Scalar(ret) return Scalar(ret)
} }
/* Sets every element of an array to a given value. */
func (img *IplImage) Set(value Scalar) {
C.cvSet(unsafe.Pointer(img), (C.CvScalar)(value), nil)
}
/* Set1D sets a particular element in the image */ /* Set1D sets a particular element in the image */
func (img *IplImage) Set1D(x int, value Scalar) { func (img *IplImage) Set1D(x int, value Scalar) {
C.cvSet1D(unsafe.Pointer(img), C.int(x), (C.CvScalar)(value)) C.cvSet1D(unsafe.Pointer(img), C.int(x), (C.CvScalar)(value))
@ -523,6 +528,15 @@ func Not(src, dst *IplImage) {
/****************************************************************************************\ /****************************************************************************************\
* Array Statistics * * Array Statistics *
\****************************************************************************************/ \****************************************************************************************/
// CvScalar cvAvg(const CvArr* arr, const CvArr* mask=NULL )
func (src *IplImage) Avg(mask *IplImage) Scalar {
return (Scalar)(C.cvAvg(unsafe.Pointer(src), unsafe.Pointer(mask)))
}
// cvEqualizeHist(const CvArr* src, CvArr* dst)
func (src *IplImage) EqualizeHist(dst *IplImage) {
C.cvEqualizeHist(unsafe.Pointer(src), unsafe.Pointer(dst))
}
/****************************************************************************************\ /****************************************************************************************\
* Discrete Linear Transforms and Related Functions * * Discrete Linear Transforms and Related Functions *
@ -531,6 +545,25 @@ func Not(src, dst *IplImage) {
/****************************************************************************************\ /****************************************************************************************\
* Dynamic data structures * * Dynamic data structures *
\****************************************************************************************/ \****************************************************************************************/
func (seq *Seq) Release() {
C.cvReleaseMemStorage(&seq.storage)
}
func (seq *Seq) Total() int {
return (int)(seq.total)
}
func (seq *Seq) HNext() *Seq {
return (*Seq)(seq.h_next)
}
func (seq *Seq) VNext() *Seq {
return (*Seq)(seq.v_next)
}
func (seq *Seq) Storage() *MemStorage {
return (*MemStorage)(seq.storage)
}
/****************************************************************************************\ /****************************************************************************************\
* Drawing * * Drawing *
@ -566,6 +599,48 @@ func Circle(image *IplImage, pt1 Point, radius int, color Scalar, thickness, lin
) )
} }
const (
CV_FONT_HERSHEY_SIMPLEX = int(C.CV_FONT_HERSHEY_SIMPLEX)
CV_FONT_HERSHEY_PLAIN = int(C.CV_FONT_HERSHEY_PLAIN)
CV_FONT_HERSHEY_DUPLEX = int(C.CV_FONT_HERSHEY_DUPLEX)
CV_FONT_HERSHEY_COMPLEX = int(C.CV_FONT_HERSHEY_COMPLEX)
CV_FONT_HERSHEY_TRIPLEX = int(C.CV_FONT_HERSHEY_TRIPLEX)
CV_FONT_HERSHEY_COMPLEX_SMALL = int(C.CV_FONT_HERSHEY_COMPLEX_SMALL)
CV_FONT_HERSHEY_SCRIPT_SIMPLEX = int(C.CV_FONT_HERSHEY_SCRIPT_SIMPLEX)
CV_FONT_HERSHEY_SCRIPT_COMPLEX = int(C.CV_FONT_HERSHEY_SCRIPT_COMPLEX)
CV_FONT_ITALIC = int(C.CV_FONT_ITALIC)
)
type Font struct {
font C.CvFont
}
//void cvInitFont(CvFont* font, int font_face, double hscale, double vscale, double shear=0, int thickness=1, int line_type=8 )
func InitFont(fontFace int, hscale, vscale, shear float32, thickness, lineType int) *Font {
font := new(Font)
C.cvInitFont(
&font.font,
C.int(fontFace),
C.double(hscale),
C.double(vscale),
C.double(shear),
C.int(thickness),
C.int(lineType),
)
return font
}
// void cvPutText(CvArr* img, const char* text, CvPoint org, const CvFont* font, CvScalar color)
func (this *Font) PutText(image *IplImage, text string, pt1 Point, color Scalar) {
C.cvPutText(
unsafe.Pointer(image),
C.CString(text),
C.cvPoint(C.int(pt1.X), C.int(pt1.Y)),
&this.font,
(C.CvScalar)(color),
)
}
//CVAPI(void) cvLine( CvArr* img, CvPoint pt1, CvPoint pt2, //CVAPI(void) cvLine( CvArr* img, CvPoint pt1, CvPoint pt2,
// CvScalar color, int thickness CV_DEFAULT(1), // CvScalar color, int thickness CV_DEFAULT(1),
// int line_type CV_DEFAULT(8), int shift CV_DEFAULT(0) ); // int line_type CV_DEFAULT(8), int shift CV_DEFAULT(0) );

View file

@ -1,9 +1,75 @@
package opencv package opencv
import ( import (
"bytes"
"io/ioutil"
"os"
"path"
"runtime"
"syscall"
"testing" "testing"
) )
func TestLoadImage2(t *testing.T) { func TestLoadImage2(t *testing.T) {
// t.Errorf("aaa") // t.Errorf("aaa")
} }
func TestInitFont(t *testing.T) {
// Will assert at the C layer on error
InitFont(CV_FONT_HERSHEY_DUPLEX, 1, 1, 0, 1, 8)
}
func TestPutText(t *testing.T) {
_, currentfile, _, _ := runtime.Caller(0)
filename := path.Join(path.Dir(currentfile), "../images/lena.jpg")
image := LoadImage(filename)
if image == nil {
t.Fatal("LoadImage fail")
}
defer image.Release()
// Write 'Hello' on the image
font := InitFont(CV_FONT_HERSHEY_DUPLEX, 1, 1, 0, 1, 8)
color := NewScalar(255, 255, 255, 0)
pos := Point{image.Width() / 2, image.Height() / 2}
font.PutText(image, "Hello", pos, color)
filename = path.Join(path.Dir(currentfile), "../images/lena_with_text.jpg")
// Uncomment this code to create the test image "../images/lena_with_text.jpg"
// It is part of the repo, and what this test compares against
//
// SaveImage(filename, image, 0)
// println("Saved file", filename)
tempfilename := path.Join(os.TempDir(), "lena_with_text.jpg")
defer syscall.Unlink(tempfilename)
SaveImage(tempfilename, image, 0)
// Compare actual image with expected image
same, err := BinaryCompare(filename, tempfilename)
if err != nil {
t.Fatal(err)
}
if !same {
t.Error("Actual file differs from expected file with text")
}
}
// Compare two files, return true if exactly the same
func BinaryCompare(file1, file2 string) (bool, error) {
f1, err := ioutil.ReadFile(file1)
if err != nil {
return false, err
}
f2, err := ioutil.ReadFile(file2)
if err != nil {
return false, err
}
return bytes.Equal(f1, f2), nil
}

View file

@ -595,6 +595,18 @@ type Box2D struct {
angle float32 angle float32
} }
func (box *Box2D) Size() Size2D32f {
return box.size
}
func (box *Box2D) Center() Point2D32f {
return box.center
}
func (box *Box2D) Angle() float32 {
return box.angle
}
type LineIterator C.CvLineIterator type LineIterator C.CvLineIterator
/************************************* CvSlice ******************************************/ /************************************* CvSlice ******************************************/
@ -605,6 +617,12 @@ const (
CV_WHOLE_SEQ_END_INDEX = C.CV_WHOLE_SEQ_END_INDEX CV_WHOLE_SEQ_END_INDEX = C.CV_WHOLE_SEQ_END_INDEX
) )
/* Equivalent to the C constant CV_WHOLE_SEQ */
func WholeSeq() Slice {
slice := C.cvSlice(C.int(0), C.CV_WHOLE_SEQ_END_INDEX)
return (Slice)(slice)
}
/************************************* CvScalar *****************************************/ /************************************* CvScalar *****************************************/
type Scalar C.CvScalar type Scalar C.CvScalar
@ -661,6 +679,18 @@ type Graph C.CvGraph
type Chain C.CvChain type Chain C.CvChain
type Contour C.CvContour type Contour C.CvContour
const (
CV_RETR_EXTERNAL = C.CV_RETR_EXTERNAL
CV_RETR_LIST = C.CV_RETR_LIST
CV_RETR_CCOMP = C.CV_RETR_CCOMP
CV_RETR_TREE = C.CV_RETR_TREE
CV_CHAIN_APPROX_NONE = C.CV_CHAIN_APPROX_NONE
CV_CHAIN_APPROX_SIMPLE = C.CV_CHAIN_APPROX_SIMPLE
CV_CHAIN_APPROX_TC89_L1 = C.CV_CHAIN_APPROX_TC89_L1
CV_CHAIN_APPROX_TC89_KCOS = C.CV_CHAIN_APPROX_TC89_KCOS
)
/****************************************************************************************\ /****************************************************************************************\
* Sequence types * * Sequence types *
\****************************************************************************************/ \****************************************************************************************/
@ -694,6 +724,15 @@ const (
type AttrList C.CvAttrList type AttrList C.CvAttrList
/****************************************************************************************/
/* Structural Analysis and Shape Descriptors */
/****************************************************************************************/
/* For use in ApproxPoly */
const (
CV_POLY_APPROX_DP = C.CV_POLY_APPROX_DP
)
/*****************************************************************************\ /*****************************************************************************\
* --- END --- * * --- END --- *
\*****************************************************************************/ \*****************************************************************************/

View file

@ -52,3 +52,78 @@ func Crop(src *IplImage, x, y, width, height int) *IplImage {
return dest return dest
} }
/* Returns a Seq of countours in an image, detected according to the parameters.
Caller must Release() the Seq returned */
func (image *IplImage) FindContours(mode, method int, offset Point) *Seq {
storage := C.cvCreateMemStorage(0)
header_size := (C.size_t)(unsafe.Sizeof(C.CvContour{}))
var seq *C.CvSeq
C.cvFindContours(
unsafe.Pointer(image),
storage,
&seq,
C.int(header_size),
C.int(mode),
C.int(method),
C.cvPoint(C.int(offset.X), C.int(offset.Y)))
return (*Seq)(seq)
}
//cvDrawContours(CvArr* img, CvSeq* contour, CvScalar externalColor, CvScalar holeColor, int maxLevel, int thickness=1, int lineType=8
func DrawContours(image *IplImage, contours *Seq, externalColor, holeColor Scalar, maxLevel, thickness, lineType int, offset Point) {
C.cvDrawContours(
unsafe.Pointer(image),
(*C.CvSeq)(contours),
(C.CvScalar)(externalColor),
(C.CvScalar)(holeColor),
C.int(maxLevel),
C.int(thickness),
C.int(lineType),
C.cvPoint(C.int(offset.X), C.int(offset.Y)))
}
// CvSeq* cvApproxPoly(const void* src_seq, int header_size, CvMemStorage* storage, int method, double eps, int recursive=0 )
func ApproxPoly(src *Seq, header_size int, storage *MemStorage, method int, eps float64, recursive int) *Seq {
seq := C.cvApproxPoly(
unsafe.Pointer(src),
C.int(header_size),
(*C.CvMemStorage)(storage),
C.int(method),
C.double(eps),
C.int(recursive))
return (*Seq)(seq)
}
// cvArcLength(const void* curve, CvSlice slice=CV_WHOLE_SEQ, int is_closed=-1 )
func ArcLength(curve *Seq, slice Slice, is_closed bool) float64 {
is_closed_int := 0
if is_closed {
is_closed_int = 1
}
return float64(C.cvArcLength(unsafe.Pointer(curve),
(C.CvSlice)(slice),
C.int(is_closed_int)))
}
func ContourPerimeter(curve *Seq) float64 {
return ArcLength(curve, WholeSeq(), true)
}
// double cvContourArea(const CvArr* contour, CvSlice slice=CV_WHOLE_SEQ, int oriented=0 )
func ContourArea(contour *Seq, slice Slice, oriented int) float64 {
return float64(C.cvContourArea(
unsafe.Pointer(contour),
(C.CvSlice)(slice),
C.int(oriented)))
}
/* points can be either CvSeq* or CvMat* */
func FitEllipse2(points unsafe.Pointer) Box2D {
box := C.cvFitEllipse2(points)
center := Point2D32f{float32(box.center.x), float32(box.center.y)}
size := Size2D32f{float32(box.size.width), float32(box.size.height)}
angle := float32(box.angle)
return Box2D{center, size, angle}
}

View file

@ -1,8 +1,10 @@
package opencv package opencv
import ( import (
"os"
"path" "path"
"runtime" "runtime"
"syscall"
"testing" "testing"
) )
@ -55,3 +57,56 @@ func TestCrop(t *testing.T) {
t.Fatalf("excepted width is 200, returned %d\n", crop.Height()) t.Fatalf("excepted width is 200, returned %d\n", crop.Height())
} }
} }
func TestFindContours(t *testing.T) {
_, currentfile, _, _ := runtime.Caller(0)
filename := path.Join(path.Dir(currentfile), "../images/pic5.png")
image := LoadImage(filename)
if image == nil {
t.Fatal("LoadImage fail")
}
defer image.Release()
grayscale := CreateImage(image.Width(), image.Height(), IPL_DEPTH_8U, 1)
CvtColor(image, grayscale, CV_BGR2GRAY)
defer grayscale.Release()
edges := CreateImage(grayscale.Width(), grayscale.Height(), grayscale.Depth(), grayscale.Channels())
defer edges.Release()
Canny(grayscale, edges, 50, 200, 3)
seq := edges.FindContours(CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE, Point{0, 0})
defer seq.Release()
contours := CreateImage(grayscale.Width(), grayscale.Height(), grayscale.Depth(), grayscale.Channels())
white := NewScalar(255, 255, 255, 0)
contours.Set(white)
black := NewScalar(0, 0, 0, 0)
red := NewScalar(0, 255, 0, 0)
for ; seq != nil; seq = seq.HNext() {
DrawContours(contours, seq, red, black, 0, 2, 8, Point{0, 0})
}
filename = path.Join(path.Dir(currentfile), "../images/pic5_contours.png")
// Uncomment this code to create the test image "../images/shapes_contours.png"
// It is part of the repo, and what this test compares against
//
//SaveImage(filename), contours, 0)
tempfilename := path.Join(os.TempDir(), "pic5_contours.png")
defer syscall.Unlink(tempfilename)
SaveImage(tempfilename, contours, 0)
// Compare actual image with expected image
same, err := BinaryCompare(filename, tempfilename)
if err != nil {
t.Fatal(err)
}
if !same {
t.Error("Expected contour file != actual contour file")
}
}

View file

@ -0,0 +1,54 @@
package main
import (
"fmt"
"os"
"path"
"github.com/lazywei/go-opencv/opencv"
)
func main() {
win := opencv.NewWindow("Go-OpenCV Webcam Face Detection")
defer win.Destroy()
cap := opencv.NewCameraCapture(0)
if cap == nil {
panic("cannot open camera")
}
defer cap.Release()
cwd, err := os.Getwd()
if err != nil {
panic(err)
}
cascade := opencv.LoadHaarClassifierCascade(path.Join(cwd, "haarcascade_frontalface_alt.xml"))
fmt.Println("Press ESC to quit")
for {
if cap.GrabFrame() {
img := cap.RetrieveFrame(1)
if img != nil {
faces := cascade.DetectObjects(img)
for _, value := range faces {
opencv.Circle(img,
opencv.Point{
value.X() + (value.Width() / 2),
value.Y() + (value.Height() / 2),
},
value.Width()/2,
opencv.ScalarAll(255.0), 1, 1, 0)
}
win.ShowImage(img)
} else {
fmt.Println("nil image")
}
}
key := opencv.WaitKey(1)
if key == 27 {
os.Exit(0)
}
}
}