mirror of
https://github.com/jehiah/TrafficSpeed.git
synced 2025-12-24 12:47:54 +08:00
object detection: add minPixels
This commit is contained in:
@@ -33,7 +33,7 @@ func (f FrameAnalysis) NeedsMore() bool {
|
||||
return len(f.images) < analysFrameCount
|
||||
}
|
||||
|
||||
func (f *FrameAnalysis) Calculate(bg *image.RGBA, blurRadius, contiguousPixels int, tolerance uint8) {
|
||||
func (f *FrameAnalysis) Calculate(bg *image.RGBA, blurRadius, contiguousPixels, minMass int, tolerance uint8) {
|
||||
log.Printf("analysis covering %d frames starting at %s", len(f.images), f.Timestamp)
|
||||
if len(f.images) == 0 {
|
||||
return
|
||||
@@ -43,7 +43,7 @@ func (f *FrameAnalysis) Calculate(bg *image.RGBA, blurRadius, contiguousPixels i
|
||||
highlight := SubImage(src, bg, tolerance)
|
||||
highlight = Blur(highlight, blurRadius)
|
||||
f.Highlight = dataImg(highlight, "image/png")
|
||||
f.Colored = dataImg(labelimg.New(highlight, contiguousPixels), "image/png")
|
||||
f.Colored = dataImg(labelimg.New(highlight, contiguousPixels, minMass), "image/png")
|
||||
|
||||
// animate 2s of video in 1s (drop 50% of frames)
|
||||
// ^^ == highlight_gif
|
||||
@@ -60,7 +60,7 @@ func (f *FrameAnalysis) Calculate(bg *image.RGBA, blurRadius, contiguousPixels i
|
||||
detected := SubImage(sim.(*image.RGBA), bgresize, tolerance)
|
||||
detected = Blur(detected, blurRadius)
|
||||
highlightGif = append(highlightGif, detected)
|
||||
colored := labelimg.New(detected, contiguousPixels)
|
||||
colored := labelimg.New(detected, contiguousPixels, 1)
|
||||
coloredGif = append(coloredGif, colored)
|
||||
}
|
||||
f.BaseGif = dataGif(NewGIF(baseGif))
|
||||
|
||||
@@ -89,7 +89,7 @@ func main() {
|
||||
p.Tolerance = getuint8("tolerance", 40)
|
||||
p.Blur = int(geti64("blur", 2))
|
||||
p.ContiguousPixels = int(geti64("contiguous_pixels", 3))
|
||||
p.MinMass = geti64("min_mass", 100)
|
||||
p.MinMass = int(geti64("min_mass", 50))
|
||||
p.Seek = getf64("seek", 0)
|
||||
p.Step = int(geti64("next", 0))
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ type Project struct {
|
||||
Tolerance uint8 `json:"tolerance"`
|
||||
Blur int `json:"blur"`
|
||||
ContiguousPixels int `json:"contiguous_pixels"`
|
||||
MinMass int64 `json:"min_mass"`
|
||||
MinMass int `json:"min_mass"`
|
||||
Seek float64 `json:"seek"`
|
||||
Calibrations []*Calibration `json:"calibrations"`
|
||||
|
||||
@@ -246,7 +246,7 @@ func (p *Project) Run() error {
|
||||
|
||||
}
|
||||
if p.Step == 5 && bgavg != nil {
|
||||
analysis.Calculate(bgavg, p.Blur, p.ContiguousPixels, p.Tolerance)
|
||||
analysis.Calculate(bgavg, p.Blur, p.ContiguousPixels, p.MinMass, p.Tolerance)
|
||||
p.Response.FrameAnalysis = append(p.Response.FrameAnalysis, *analysis)
|
||||
}
|
||||
|
||||
|
||||
@@ -17,16 +17,16 @@ func abs(i int) int {
|
||||
// type LabelImage image.Paletted
|
||||
|
||||
// New creates a new paletted image by detecting contiguous blobs of non-zero color in `g`.
|
||||
// overlap is defined as +/- distance on x and y axis. Diagonal overlap is not detected for
|
||||
// distance > 1
|
||||
func New(g *image.Gray, distance int) *image.Paletted {
|
||||
// overlap is defined as +/- contiguous pixes on x and y axis. Diagonal overlap is detected for
|
||||
// contiguousPixels > 1. Groups of pixels smaller than minPixels are not returned
|
||||
func New(g *image.Gray, contiguousPixels, minPixels int) *image.Paletted {
|
||||
pb := image.Rect(0, 0, g.Bounds().Dx(), g.Bounds().Dy())
|
||||
// log.Printf("new image %v", pb)
|
||||
p := image.NewPaletted(pb, nil)
|
||||
if distance < 1 {
|
||||
if contiguousPixels < 1 {
|
||||
panic("negative distance not allowed")
|
||||
}
|
||||
minOffset, maxOffset := -1*distance, distance
|
||||
minOffset, maxOffset := -1*contiguousPixels, contiguousPixels
|
||||
|
||||
for x := g.Rect.Min.X; x < g.Rect.Max.X; x++ {
|
||||
for y := g.Rect.Min.Y; y < g.Rect.Max.Y; y++ {
|
||||
@@ -39,7 +39,7 @@ func New(g *image.Gray, distance int) *image.Paletted {
|
||||
// do overlap checks to see if this is a new point or if it overlaps
|
||||
for xo := minOffset; xo <= maxOffset; xo++ {
|
||||
for yo := minOffset; yo <= maxOffset; yo++ {
|
||||
if abs(xo)+abs(yo) > maxOffset{
|
||||
if abs(xo)+abs(yo) > maxOffset {
|
||||
continue
|
||||
}
|
||||
if xo == 0 && yo == 0 {
|
||||
@@ -89,6 +89,21 @@ func New(g *image.Gray, distance int) *image.Paletted {
|
||||
p.SetColorIndex(x-g.Rect.Min.X, y-g.Rect.Min.Y, i)
|
||||
}
|
||||
}
|
||||
|
||||
// detect groups smaller than minPixels
|
||||
if minPixels > 1 {
|
||||
var hits [255]int
|
||||
for _, pixel := range p.Pix {
|
||||
hits[pixel]++
|
||||
}
|
||||
// walk in reverse
|
||||
for n := 254; n > 0; n-- {
|
||||
if hits[n] > 0 && hits[n] <= minPixels {
|
||||
replaceColor(p, uint8(n), 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
p.Palette = Glasbey
|
||||
return p
|
||||
}
|
||||
|
||||
@@ -1,25 +1,88 @@
|
||||
package labelimg
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"image"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestLabelimg(t *testing.T) {
|
||||
func prettyGrey(g *image.Gray) string {
|
||||
return prettyPix(g.Pix, g.Rect, g.PixOffset)
|
||||
}
|
||||
func prettyPaletted(g *image.Paletted) string {
|
||||
return prettyPix(g.Pix, g.Rect, g.PixOffset)
|
||||
}
|
||||
|
||||
l := &image.Gray{
|
||||
Pix: []uint8{3, 3, 0, 4,
|
||||
3, 0, 4, 4,
|
||||
},
|
||||
Stride: 4,
|
||||
Rect: image.Rect(1, 1, 5, 3), // 4 x 2
|
||||
func prettyPix(pix []uint8, r image.Rectangle, pixOffset func(int, int) int) string {
|
||||
var s string = "\n"
|
||||
for y := r.Min.Y; y < r.Max.Y; y++ {
|
||||
for x := r.Min.X; x < r.Max.X; x++ {
|
||||
s += fmt.Sprintf("%02x", pix[pixOffset(x, y)])
|
||||
}
|
||||
s += "\n"
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func TestLabelimg(t *testing.T) {
|
||||
type testCase struct {
|
||||
Rect image.Rectangle
|
||||
Pix []uint8
|
||||
Expect []uint8
|
||||
ContiguousPixels int
|
||||
MinPixels int
|
||||
}
|
||||
|
||||
labeled := New(l, 1)
|
||||
|
||||
assert.Equal(t, []uint8{1, 1, 0, 2,
|
||||
1, 0, 2, 2}, labeled.Pix)
|
||||
tests := []testCase{
|
||||
{
|
||||
Rect: image.Rect(1, 1, 5, 3), // 4 x 2
|
||||
Pix: []uint8{
|
||||
3, 3, 0, 4,
|
||||
3, 0, 4, 4,
|
||||
},
|
||||
Expect: []uint8{
|
||||
1, 1, 0, 2,
|
||||
1, 0, 2, 2,
|
||||
},
|
||||
ContiguousPixels: 1,
|
||||
MinPixels: 1,
|
||||
},
|
||||
{
|
||||
Rect: image.Rect(0, 0, 4, 4),
|
||||
Pix: []uint8{
|
||||
3, 3, 0, 4,
|
||||
3, 0, 0, 4,
|
||||
0, 0, 4, 4,
|
||||
0, 0, 4, 4,
|
||||
},
|
||||
Expect: []uint8{
|
||||
0, 0, 0, 1,
|
||||
0, 0, 0, 1,
|
||||
0, 0, 1, 1,
|
||||
0, 0, 1, 1,
|
||||
},
|
||||
ContiguousPixels: 1,
|
||||
MinPixels: 3,
|
||||
},
|
||||
}
|
||||
for i, tc := range tests {
|
||||
tc := tc
|
||||
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
|
||||
t.Parallel()
|
||||
start := &image.Gray{
|
||||
Pix: tc.Pix,
|
||||
Rect: tc.Rect,
|
||||
Stride: tc.Rect.Dx(),
|
||||
}
|
||||
t.Logf("start %s", prettyGrey(start))
|
||||
|
||||
labeled := New(start, tc.ContiguousPixels, tc.MinPixels)
|
||||
t.Logf("labeled %s", prettyPaletted(labeled))
|
||||
start.Pix = tc.Expect
|
||||
t.Logf("Expect %s", prettyGrey(start))
|
||||
assert.Equal(t, tc.Expect, labeled.Pix)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user