summaryrefslogtreecommitdiffstats
path: root/Godeps/_workspace/src/code.google.com/p/graphics-go/graphics/detect/detect.go
diff options
context:
space:
mode:
Diffstat (limited to 'Godeps/_workspace/src/code.google.com/p/graphics-go/graphics/detect/detect.go')
-rw-r--r--Godeps/_workspace/src/code.google.com/p/graphics-go/graphics/detect/detect.go133
1 files changed, 133 insertions, 0 deletions
diff --git a/Godeps/_workspace/src/code.google.com/p/graphics-go/graphics/detect/detect.go b/Godeps/_workspace/src/code.google.com/p/graphics-go/graphics/detect/detect.go
new file mode 100644
index 000000000..dde941cbe
--- /dev/null
+++ b/Godeps/_workspace/src/code.google.com/p/graphics-go/graphics/detect/detect.go
@@ -0,0 +1,133 @@
+// Copyright 2011 The Graphics-Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package detect
+
+import (
+ "image"
+ "math"
+)
+
+// Feature is a Haar-like feature.
+type Feature struct {
+ Rect image.Rectangle
+ Weight float64
+}
+
+// Classifier is a set of features with a threshold.
+type Classifier struct {
+ Feature []Feature
+ Threshold float64
+ Left float64
+ Right float64
+}
+
+// CascadeStage is a cascade of classifiers.
+type CascadeStage struct {
+ Classifier []Classifier
+ Threshold float64
+}
+
+// Cascade is a degenerate tree of Haar-like classifiers.
+type Cascade struct {
+ Stage []CascadeStage
+ Size image.Point
+}
+
+// Match returns true if the full image is classified as an object.
+func (c *Cascade) Match(m image.Image) bool {
+ return c.classify(newWindow(m))
+}
+
+// Find returns a set of areas of m that match the feature cascade c.
+func (c *Cascade) Find(m image.Image) []image.Rectangle {
+ // TODO(crawshaw): Consider de-duping strategies.
+ matches := []image.Rectangle{}
+ w := newWindow(m)
+
+ b := m.Bounds()
+ origScale := c.Size
+ for s := origScale; s.X < b.Dx() && s.Y < b.Dy(); s = s.Add(s.Div(10)) {
+ // translate region and classify
+ tx := image.Pt(s.X/10, 0)
+ ty := image.Pt(0, s.Y/10)
+ for r := image.Rect(0, 0, s.X, s.Y).Add(b.Min); r.In(b); r = r.Add(ty) {
+ for r1 := r; r1.In(b); r1 = r1.Add(tx) {
+ if c.classify(w.subWindow(r1)) {
+ matches = append(matches, r1)
+ }
+ }
+ }
+ }
+ return matches
+}
+
+type window struct {
+ mi *integral
+ miSq *integral
+ rect image.Rectangle
+ invArea float64
+ stdDev float64
+}
+
+func (w *window) init() {
+ w.invArea = 1 / float64(w.rect.Dx()*w.rect.Dy())
+ mean := float64(w.mi.sum(w.rect)) * w.invArea
+ vr := float64(w.miSq.sum(w.rect))*w.invArea - mean*mean
+ if vr < 0 {
+ vr = 1
+ }
+ w.stdDev = math.Sqrt(vr)
+}
+
+func newWindow(m image.Image) *window {
+ mi, miSq := newIntegrals(m)
+ res := &window{
+ mi: mi,
+ miSq: miSq,
+ rect: m.Bounds(),
+ }
+ res.init()
+ return res
+}
+
+func (w *window) subWindow(r image.Rectangle) *window {
+ res := &window{
+ mi: w.mi,
+ miSq: w.miSq,
+ rect: r,
+ }
+ res.init()
+ return res
+}
+
+func (c *Classifier) classify(w *window, pr *projector) float64 {
+ s := 0.0
+ for _, f := range c.Feature {
+ s += float64(w.mi.sum(pr.rect(f.Rect))) * f.Weight
+ }
+ s *= w.invArea // normalize to maintain scale invariance
+ if s < c.Threshold*w.stdDev {
+ return c.Left
+ }
+ return c.Right
+}
+
+func (s *CascadeStage) classify(w *window, pr *projector) bool {
+ sum := 0.0
+ for _, c := range s.Classifier {
+ sum += c.classify(w, pr)
+ }
+ return sum >= s.Threshold
+}
+
+func (c *Cascade) classify(w *window) bool {
+ pr := newProjector(w.rect, image.Rectangle{image.Pt(0, 0), c.Size})
+ for _, s := range c.Stage {
+ if !s.classify(w, pr) {
+ return false
+ }
+ }
+ return true
+}