integral.go 2.1 KB

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