diff --git a/images/pic5_contours.png b/images/pic5_contours.png new file mode 100644 index 0000000..ba18b18 Binary files /dev/null and b/images/pic5_contours.png differ 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") + } + }