github.com/aloncn/graphics-go@v0.0.1/graphics/detect/integral.go (about)

     1  // Copyright 2011 The Graphics-Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package detect
     6  
     7  import (
     8  	"image"
     9  	"image/draw"
    10  )
    11  
    12  // integral is an image.Image-like structure that stores the cumulative
    13  // sum of the preceding pixels. This allows for O(1) summation of any
    14  // rectangular region within the image.
    15  type integral struct {
    16  	// pix holds the cumulative sum of the image's pixels. The pixel at
    17  	// (x, y) starts at pix[(y-rect.Min.Y)*stride + (x-rect.Min.X)*1].
    18  	pix    []uint64
    19  	stride int
    20  	rect   image.Rectangle
    21  }
    22  
    23  func (p *integral) at(x, y int) uint64 {
    24  	return p.pix[(y-p.rect.Min.Y)*p.stride+(x-p.rect.Min.X)]
    25  }
    26  
    27  func (p *integral) sum(b image.Rectangle) uint64 {
    28  	c := p.at(b.Max.X-1, b.Max.Y-1)
    29  	inY := b.Min.Y > p.rect.Min.Y
    30  	inX := b.Min.X > p.rect.Min.X
    31  	if inY && inX {
    32  		c += p.at(b.Min.X-1, b.Min.Y-1)
    33  	}
    34  	if inY {
    35  		c -= p.at(b.Max.X-1, b.Min.Y-1)
    36  	}
    37  	if inX {
    38  		c -= p.at(b.Min.X-1, b.Max.Y-1)
    39  	}
    40  	return c
    41  }
    42  
    43  func (m *integral) integrate() {
    44  	b := m.rect
    45  	for y := b.Min.Y; y < b.Max.Y; y++ {
    46  		for x := b.Min.X; x < b.Max.X; x++ {
    47  			c := uint64(0)
    48  			if y > b.Min.Y && x > b.Min.X {
    49  				c += m.at(x-1, y)
    50  				c += m.at(x, y-1)
    51  				c -= m.at(x-1, y-1)
    52  			} else if y > b.Min.Y {
    53  				c += m.at(b.Min.X, y-1)
    54  			} else if x > b.Min.X {
    55  				c += m.at(x-1, b.Min.Y)
    56  			}
    57  			m.pix[(y-m.rect.Min.Y)*m.stride+(x-m.rect.Min.X)] += c
    58  		}
    59  	}
    60  }
    61  
    62  // newIntegrals returns the integral and the squared integral.
    63  func newIntegrals(src image.Image) (*integral, *integral) {
    64  	b := src.Bounds()
    65  	srcg, ok := src.(*image.Gray)
    66  	if !ok {
    67  		srcg = image.NewGray(b)
    68  		draw.Draw(srcg, b, src, b.Min, draw.Src)
    69  	}
    70  
    71  	m := integral{
    72  		pix:    make([]uint64, b.Max.Y*b.Max.X),
    73  		stride: b.Max.X,
    74  		rect:   b,
    75  	}
    76  	mSq := integral{
    77  		pix:    make([]uint64, b.Max.Y*b.Max.X),
    78  		stride: b.Max.X,
    79  		rect:   b,
    80  	}
    81  	for y := b.Min.Y; y < b.Max.Y; y++ {
    82  		for x := b.Min.X; x < b.Max.X; x++ {
    83  			os := (y-b.Min.Y)*srcg.Stride + x - b.Min.X
    84  			om := (y-b.Min.Y)*m.stride + x - b.Min.X
    85  			c := uint64(srcg.Pix[os])
    86  			m.pix[om] = c
    87  			mSq.pix[om] = c * c
    88  		}
    89  	}
    90  	m.integrate()
    91  	mSq.integrate()
    92  	return &m, &mSq
    93  }