func processImage(input *cv.IplImage) (*cv.IplImage, []Rect) { storage := cv.NewMemStorage(0) defer storage.Release() hsv := cv.NewImage(input.Size(), 8, 3) defer hsv.Release() sat := cv.NewImage(input.Size(), 8, 1) defer sat.Release() val := cv.NewImage(input.Size(), 8, 1) defer val.Release() threshSat := cv.NewImage(input.Size(), 8, 1) defer threshSat.Release() threshVal := cv.NewImage(input.Size(), 8, 1) defer threshVal.Release() thresh := cv.NewImage(input.Size(), 8, 1) cv.CvtColor(input, hsv, cv.BGR2HSV) cv.Split(hsv, nil, sat, nil, nil) cv.Split(hsv, nil, nil, val, nil) cv.Threshold(sat, threshSat, 70, 255, cv.THRESH_BINARY) //cv.ShowImage(satWindowName, threshSat) cv.Threshold(val, threshVal, 70, 255, cv.THRESH_BINARY_INV) //cv.ShowImage(valWindowName, threshVal) cv.And(threshVal, threshSat, thresh, nil) cv.Dilate(thresh, thresh, nil, 1) cv.Erode(thresh, thresh, nil, 1) rects := make([]Rect, 0) threshClone := thresh.Clone() defer threshClone.Release() contour, _ := cv.FindContours(threshClone, storage, cv.RETR_LIST, cv.CHAIN_APPROX_SIMPLE, cv.Point{}) for ; !contour.IsZero(); contour = contour.Next() { result := cv.ApproxPoly(contour, storage, cv.POLY_APPROX_DP, cv.ContourPerimeter(contour)*0.02, 0) if result.Len() != 4 || cv.ContourArea(result, cv.WHOLE_SEQ, false) < 1000 || !cv.CheckContourConvexity(result) { continue } var r Rect for i := 0; i < 4; i++ { r[i] = result.PointAt(i) } rects = append(rects, r) } return thresh, rects }
func findRectangles(img *cv.IplImage) [][4]cv.Point { storage := cv.NewMemStorage(0) defer storage.Release() sz := cv.Size{img.Width &^ 1, img.Height &^ 1} timg := img.Clone() defer timg.Release() gray := cv.NewImage(sz, 8, 1) defer gray.Release() pyr := cv.NewImage(cv.Size{sz.Width / 2, sz.Height / 2}, 8, 3) defer pyr.Release() rects := make([][4]cv.Point, 0) timg.SetROI(cv.Rect{0, 0, sz.Width, sz.Height}) cv.PyrDown(timg, pyr, cv.GAUSSIAN_5x5) cv.PyrUp(timg, pyr, cv.GAUSSIAN_5x5) tgray := cv.NewImage(sz, 8, 1) defer tgray.Release() for channel := 1; channel <= 3; channel++ { timg.SetCOI(channel) cv.Copy(timg, tgray, nil) cv.Threshold(tgray, gray, lowThreshold, highThreshold, cv.THRESH_BINARY) cv.Dilate(gray, gray, nil, 10) cv.Erode(gray, gray, nil, 8) contour, _ := cv.FindContours(gray, storage, cv.RETR_LIST, cv.CHAIN_APPROX_SIMPLE, cv.Point{0, 0}) for ; !contour.IsZero(); contour = contour.Next() { result := cv.ApproxPoly(contour, storage, cv.POLY_APPROX_DP, cv.ContourPerimeter(contour)*0.02, 0) if result.Len() != 4 || cv.ContourArea(result, cv.WHOLE_SEQ, false) < 1000 || !cv.CheckContourConvexity(result) { continue } var r [4]cv.Point for i := 0; i < 4; i++ { r[i] = result.PointAt(i) } s := 0.0 // TODO: Check this boundary for i := 2; i < 5; i++ { t := math.Abs(angle(result.PointAt(i%4), result.PointAt((i-2)%4), result.PointAt((i-1)%4))) if t > s { s = t } } // originally 0.3 for strict 90 degrees, may need to increase slightly if s < 0.4 { points := r sort.Sort(ByY(points[:])) distance := (points[2].Y+points[3].Y)/2 - (points[0].Y+points[1].Y)/2 fmt.Println("average height: ", distance) rects = append(rects, r) } } } return rects }