You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
93 lines
2.1 KiB
93 lines
2.1 KiB
// 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" |
|
"image/draw" |
|
) |
|
|
|
// integral is an image.Image-like structure that stores the cumulative |
|
// sum of the preceding pixels. This allows for O(1) summation of any |
|
// rectangular region within the image. |
|
type integral struct { |
|
// pix holds the cumulative sum of the image's pixels. The pixel at |
|
// (x, y) starts at pix[(y-rect.Min.Y)*stride + (x-rect.Min.X)*1]. |
|
pix []uint64 |
|
stride int |
|
rect image.Rectangle |
|
} |
|
|
|
func (p *integral) at(x, y int) uint64 { |
|
return p.pix[(y-p.rect.Min.Y)*p.stride+(x-p.rect.Min.X)] |
|
} |
|
|
|
func (p *integral) sum(b image.Rectangle) uint64 { |
|
c := p.at(b.Max.X-1, b.Max.Y-1) |
|
inY := b.Min.Y > p.rect.Min.Y |
|
inX := b.Min.X > p.rect.Min.X |
|
if inY && inX { |
|
c += p.at(b.Min.X-1, b.Min.Y-1) |
|
} |
|
if inY { |
|
c -= p.at(b.Max.X-1, b.Min.Y-1) |
|
} |
|
if inX { |
|
c -= p.at(b.Min.X-1, b.Max.Y-1) |
|
} |
|
return c |
|
} |
|
|
|
func (m *integral) integrate() { |
|
b := m.rect |
|
for y := b.Min.Y; y < b.Max.Y; y++ { |
|
for x := b.Min.X; x < b.Max.X; x++ { |
|
c := uint64(0) |
|
if y > b.Min.Y && x > b.Min.X { |
|
c += m.at(x-1, y) |
|
c += m.at(x, y-1) |
|
c -= m.at(x-1, y-1) |
|
} else if y > b.Min.Y { |
|
c += m.at(b.Min.X, y-1) |
|
} else if x > b.Min.X { |
|
c += m.at(x-1, b.Min.Y) |
|
} |
|
m.pix[(y-m.rect.Min.Y)*m.stride+(x-m.rect.Min.X)] += c |
|
} |
|
} |
|
} |
|
|
|
// newIntegrals returns the integral and the squared integral. |
|
func newIntegrals(src image.Image) (*integral, *integral) { |
|
b := src.Bounds() |
|
srcg, ok := src.(*image.Gray) |
|
if !ok { |
|
srcg = image.NewGray(b) |
|
draw.Draw(srcg, b, src, b.Min, draw.Src) |
|
} |
|
|
|
m := integral{ |
|
pix: make([]uint64, b.Max.Y*b.Max.X), |
|
stride: b.Max.X, |
|
rect: b, |
|
} |
|
mSq := integral{ |
|
pix: make([]uint64, b.Max.Y*b.Max.X), |
|
stride: b.Max.X, |
|
rect: b, |
|
} |
|
for y := b.Min.Y; y < b.Max.Y; y++ { |
|
for x := b.Min.X; x < b.Max.X; x++ { |
|
os := (y-b.Min.Y)*srcg.Stride + x - b.Min.X |
|
om := (y-b.Min.Y)*m.stride + x - b.Min.X |
|
c := uint64(srcg.Pix[os]) |
|
m.pix[om] = c |
|
mSq.pix[om] = c * c |
|
} |
|
} |
|
m.integrate() |
|
mSq.integrate() |
|
return &m, &mSq |
|
}
|
|
|