Files
TrafficSpeed/internal/project/position.go
Jehiah Czebotar b62fd13263 go modules
2020-04-07 22:00:32 -04:00

105 lines
2.5 KiB
Go

package project
import (
"fmt"
"image"
"math"
"time"
"github.com/jehiah/TrafficSpeed/img/labelimg"
)
// Position matches Position in position.jl
type Position struct {
X float64 `json:"x"`
Y float64 `json:"y"`
Mass int `json:"mass"`
XSpan []int `json:"xspan"` // [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]
YSpan []int `json:"yspan"`
}
func (p Position) Span() string {
mm := func(d []int) (min int, max int) {
for i, n := range d {
if n < min || i == 0 {
min = n
}
if n > max || i == 0 {
max = n
}
}
return
}
xmin, xmax := mm(p.XSpan)
ymin, ymax := mm(p.YSpan)
return fmt.Sprintf("x:%d-%d y:%d-%d", xmin, xmax, ymin, ymax)
}
func (p Position) Size() string {
return fmt.Sprintf("%dx%d", len(p.XSpan), len(p.YSpan))
}
type FramePosition struct {
Frame int
Time time.Duration
Positions []labelimg.Label
}
type VehiclePosition struct {
Frame int
Time time.Duration
VehicleID int
Position labelimg.Label
}
// TrackVehicles tracks detected objects and correlates across frames
// based on logic from identifyvehicles from https://github.com/mbauman/TrafficSpeed/blob/master/TrafficSpeed.ipynb
func TrackVehicles(frames []FramePosition) []VehiclePosition {
var vehicleCount int
var vehicles []VehiclePosition
var lastFrameVehicles []VehiclePosition
for _, frame := range frames {
var currentFrameVehicles []VehiclePosition
for _, position := range frame.Positions {
// is position overlap from lastFrame
var vehicleID int
// TODO: use median point not center
if closest := ClosestPosition(position.Center, lastFrameVehicles); position.Center.In(closest.Position.Bounds) {
vehicleID = closest.VehicleID
} else {
vehicleCount++
vehicleID = vehicleCount
}
currentFrameVehicles = append(currentFrameVehicles, VehiclePosition{
Frame: frame.Frame,
Time: frame.Time,
VehicleID: vehicleID,
Position: position,
})
}
lastFrameVehicles = currentFrameVehicles
vehicles = append(vehicles, currentFrameVehicles...)
}
return vehicles
}
func ClosestPosition(point image.Point, v []VehiclePosition) VehiclePosition {
var closest VehiclePosition
var min float64 = -1
for _, p := range v {
// TODO: use median point not center
d := distance(point, p.Position.Center)
if min == -1 || d < min {
min = d
closest = p
}
}
return closest
}
func distance(a, b image.Point) float64 {
x := math.Abs(float64(a.X) - float64(b.X))
y := math.Abs(float64(a.Y) - float64(b.Y))
return math.Sqrt((x * x) + (y * y))
}