From 8f000e16ffa2aa3d640e7a1cf0221d12abb15905 Mon Sep 17 00:00:00 2001 From: David Oram Date: Tue, 1 Sep 2015 06:29:03 +1200 Subject: [PATCH 1/3] Created basic functionality --- images/shapes.png | Bin 0 -> 8262 bytes opencv/cxtype.go | 18 ++++++++++++++++++ opencv/imgproc.go | 29 +++++++++++++++++++++++++++++ opencv/imgproc_test.go | 22 ++++++++++++++++++++++ 4 files changed, 69 insertions(+) create mode 100644 images/shapes.png diff --git a/images/shapes.png b/images/shapes.png new file mode 100644 index 0000000000000000000000000000000000000000..357bf4efb5267a1619732fa5afd8c3667d18b98f GIT binary patch literal 8262 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 literal 0 HcmV?d00001 diff --git a/opencv/cxtype.go b/opencv/cxtype.go index 9fe7603..9037ef0 100644 --- a/opencv/cxtype.go +++ b/opencv/cxtype.go @@ -661,6 +661,24 @@ type Graph C.CvGraph type Chain C.CvChain type Contour C.CvContour +type ContourType struct { + mode C.int + method C.int + offset Point +} + +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 * \****************************************************************************************/ diff --git a/opencv/imgproc.go b/opencv/imgproc.go index 93b8070..83ae702 100644 --- a/opencv/imgproc.go +++ b/opencv/imgproc.go @@ -52,3 +52,32 @@ func Crop(src *IplImage, x, y, width, height int) *IplImage { return dest } + +func CreateContourType() *ContourType { + return &ContourType{CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE, Point{0, 0}} +} + +func (this *ContourType) FindContours(image *IplImage) []*Contour { + 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), + this.mode, + this.method, + C.cvPoint(C.int(this.offset.X), C.int(this.offset.Y))) + + var contours []*Contour + for i := 0; i < (int)(seq.total); i++ { + contour := (*Contour)((*_Ctype_CvContour)(unsafe.Pointer(C.cvGetSeqElem(seq, C.int(i))))) + contours = append(contours, contour) + } + + storage_c := (*C.CvMemStorage)(storage) + C.cvReleaseMemStorage(&storage_c) + + return contours +} diff --git a/opencv/imgproc_test.go b/opencv/imgproc_test.go index 85ed22e..759dc06 100644 --- a/opencv/imgproc_test.go +++ b/opencv/imgproc_test.go @@ -1,6 +1,7 @@ package opencv import ( + "log" "path" "runtime" "testing" @@ -55,3 +56,24 @@ func TestCrop(t *testing.T) { 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/shapes.png") + + image := LoadImage(filename) + if image == nil { + t.Fatal("LoadImage fail") + } + defer image.Release() + + grayscale_image := CreateImage(image.Width(), image.Height(), IPL_DEPTH_8U, 1) + CvtColor(image, grayscale_image, CV_BGR2GRAY) + defer grayscale_image.Release() + + cType := CreateContourType() + contours := cType.FindContours(grayscale_image) + for i, c := range contours { + log.Printf("Contour[%v] = %v", i, c) + } +} From 02da2d4700f22ded07c09bcb007cc35202d341bb Mon Sep 17 00:00:00 2001 From: David Oram Date: Thu, 10 Sep 2015 16:51:38 +1200 Subject: [PATCH 2/3] Added functions: - FindContours - DrawContours - Set - EqualizeHist and associated constants --- images/pic5_contours.png | Bin 0 -> 5180 bytes opencv/cv.go | 6 ++++- opencv/cxcore.go | 17 +++++++++++++ opencv/imgproc.go | 30 +++++++++++++--------- opencv/imgproc_test.go | 53 ++++++++++++++++++++++++++++++++------- 5 files changed, 84 insertions(+), 22 deletions(-) create mode 100644 images/pic5_contours.png diff --git a/images/pic5_contours.png b/images/pic5_contours.png new file mode 100644 index 0000000000000000000000000000000000000000..ba18b187073f8790cd600c1fd239be72bed126fe GIT binary patch literal 5180 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 I^|QYJ0r(G^2><{9 literal 0 HcmV?d00001 diff --git a/opencv/cv.go b/opencv/cv.go index c41ddcc..2e5e689 100644 --- a/opencv/cv.go +++ b/opencv/cv.go @@ -23,7 +23,11 @@ const ( CV_BGR2BGRA = C.CV_BGR2BGRA 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_8S = C.CV_8S diff --git a/opencv/cxcore.go b/opencv/cxcore.go index 610d933..f2c8080 100644 --- a/opencv/cxcore.go +++ b/opencv/cxcore.go @@ -113,6 +113,11 @@ func (img *IplImage) GetROI() Rect { return Rect(r) } +/* Equalizes the histogram of a grayscale image */ +func (img *IplImage) EqualizeHist(dest *IplImage) { + C.cvEqualizeHist(unsafe.Pointer(img), unsafe.Pointer(dest)) +} + /* Reshape changes shape of the image without copying data. A value of `0` means that channels or rows remain unchanged. @@ -142,6 +147,11 @@ func (img *IplImage) Get3D(x, y, z int) Scalar { 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 */ func (img *IplImage) Set1D(x int, value Scalar) { C.cvSet1D(unsafe.Pointer(img), C.int(x), (C.CvScalar)(value)) @@ -531,6 +541,13 @@ func Not(src, dst *IplImage) { /****************************************************************************************\ * Dynamic data structures * \****************************************************************************************/ +func (seq *Seq) Release() { + C.cvReleaseMemStorage(&seq.storage) +} + +func (seq *Seq) Total() int { + return (int)(seq.total) +} /****************************************************************************************\ * Drawing * diff --git a/opencv/imgproc.go b/opencv/imgproc.go index 83ae702..5d0676f 100644 --- a/opencv/imgproc.go +++ b/opencv/imgproc.go @@ -54,10 +54,12 @@ func Crop(src *IplImage, x, y, width, height int) *IplImage { } func CreateContourType() *ContourType { - return &ContourType{CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE, Point{0, 0}} + return &ContourType{mode: CV_RETR_EXTERNAL, method: CV_CHAIN_APPROX_SIMPLE, offset: Point{0, 0}} } -func (this *ContourType) FindContours(image *IplImage) []*Contour { +/* Returns a Seq of countours in an image, detected according to the parameters in ContourType. + Caller must Release() the Seq returned */ +func (this *ContourType) FindContours(image *IplImage) *Seq { storage := C.cvCreateMemStorage(0) header_size := (C.size_t)(unsafe.Sizeof(C.CvContour{})) var seq *C.CvSeq @@ -70,14 +72,18 @@ func (this *ContourType) FindContours(image *IplImage) []*Contour { this.method, C.cvPoint(C.int(this.offset.X), C.int(this.offset.Y))) - var contours []*Contour - for i := 0; i < (int)(seq.total); i++ { - contour := (*Contour)((*_Ctype_CvContour)(unsafe.Pointer(C.cvGetSeqElem(seq, C.int(i))))) - contours = append(contours, contour) - } - - storage_c := (*C.CvMemStorage)(storage) - C.cvReleaseMemStorage(&storage_c) - - return contours + 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))) } diff --git a/opencv/imgproc_test.go b/opencv/imgproc_test.go index 759dc06..c986aec 100644 --- a/opencv/imgproc_test.go +++ b/opencv/imgproc_test.go @@ -1,10 +1,11 @@ package opencv import ( - "log" "path" "runtime" + "os" "testing" + "syscall" ) func TestResize(t *testing.T) { @@ -59,7 +60,7 @@ func TestCrop(t *testing.T) { func TestFindContours(t *testing.T) { _, currentfile, _, _ := runtime.Caller(0) - filename := path.Join(path.Dir(currentfile), "../images/shapes.png") + filename := path.Join(path.Dir(currentfile), "../images/pic5.png") image := LoadImage(filename) if image == nil { @@ -67,13 +68,47 @@ func TestFindContours(t *testing.T) { } defer image.Release() - grayscale_image := CreateImage(image.Width(), image.Height(), IPL_DEPTH_8U, 1) - CvtColor(image, grayscale_image, CV_BGR2GRAY) - defer grayscale_image.Release() + grayscale := CreateImage(image.Width(), image.Height(), IPL_DEPTH_8U, 1) + CvtColor(image, grayscale, CV_BGR2GRAY) + defer grayscale.Release() - cType := CreateContourType() - contours := cType.FindContours(grayscale_image) - for i, c := range contours { - log.Printf("Contour[%v] = %v", i, c) + + edges := CreateImage(grayscale.Width(), grayscale.Height(), grayscale.Depth(), grayscale.Channels()) + defer edges.Release() + Canny(grayscale, edges, 50, 200, 3) + + contourType := CreateContourType() + seq := contourType.FindContours(edges) + 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)(seq.h_next) { + 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") + } + } From f812503e45f8c3a5bb6b397e09ff3249036da9d8 Mon Sep 17 00:00:00 2001 From: David Oram Date: Thu, 10 Sep 2015 16:56:27 +1200 Subject: [PATCH 3/3] Refactored FindCountours to pass all parameters needed --- opencv/cxtype.go | 6 ------ opencv/imgproc.go | 14 +++++--------- opencv/imgproc_test.go | 3 +-- 3 files changed, 6 insertions(+), 17 deletions(-) diff --git a/opencv/cxtype.go b/opencv/cxtype.go index 9037ef0..984baa4 100644 --- a/opencv/cxtype.go +++ b/opencv/cxtype.go @@ -661,12 +661,6 @@ type Graph C.CvGraph type Chain C.CvChain type Contour C.CvContour -type ContourType struct { - mode C.int - method C.int - offset Point -} - const ( CV_RETR_EXTERNAL = C.CV_RETR_EXTERNAL CV_RETR_LIST = C.CV_RETR_LIST diff --git a/opencv/imgproc.go b/opencv/imgproc.go index 5d0676f..8861bab 100644 --- a/opencv/imgproc.go +++ b/opencv/imgproc.go @@ -53,13 +53,9 @@ func Crop(src *IplImage, x, y, width, height int) *IplImage { return dest } -func CreateContourType() *ContourType { - return &ContourType{mode: CV_RETR_EXTERNAL, method: CV_CHAIN_APPROX_SIMPLE, offset: Point{0, 0}} -} - -/* Returns a Seq of countours in an image, detected according to the parameters in ContourType. +/* Returns a Seq of countours in an image, detected according to the parameters. Caller must Release() the Seq returned */ -func (this *ContourType) FindContours(image *IplImage) *Seq { +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 @@ -68,9 +64,9 @@ func (this *ContourType) FindContours(image *IplImage) *Seq { storage, &seq, C.int(header_size), - this.mode, - this.method, - C.cvPoint(C.int(this.offset.X), C.int(this.offset.Y))) + C.int(mode), + C.int(method), + C.cvPoint(C.int(offset.X), C.int(offset.Y))) return (*Seq)(seq) } diff --git a/opencv/imgproc_test.go b/opencv/imgproc_test.go index c986aec..9f4509b 100644 --- a/opencv/imgproc_test.go +++ b/opencv/imgproc_test.go @@ -77,8 +77,7 @@ func TestFindContours(t *testing.T) { defer edges.Release() Canny(grayscale, edges, 50, 200, 3) - contourType := CreateContourType() - seq := contourType.FindContours(edges) + 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())