robocar-road/pkg/part/part.go

145 lines
3.4 KiB
Go
Raw Normal View History

2020-01-04 13:10:36 +00:00
package part
import (
"github.com/cyrilix/robocar-base/service"
"github.com/cyrilix/robocar-protobuf/go/events"
mqtt "github.com/eclipse/paho.mqtt.golang"
2021-10-12 21:15:05 +00:00
"go.uber.org/zap"
2020-01-04 13:10:36 +00:00
"gocv.io/x/gocv"
2022-01-03 18:05:47 +00:00
"google.golang.org/protobuf/proto"
2021-10-12 21:15:05 +00:00
"log"
2020-01-04 13:10:36 +00:00
)
type RoadPart struct {
client mqtt.Client
frameChan chan frameToProcess
readyForNext chan interface{}
cancel chan interface{}
roadDetector *RoadDetector
horizon int
cameraTopic, roadTopic string
}
func NewRoadPart(client mqtt.Client, horizon int, cameraTopic, roadTopic string) *RoadPart {
return &RoadPart{
client: client,
frameChan: make(chan frameToProcess),
cancel: make(chan interface{}),
roadDetector: NewRoadDetector(),
horizon: horizon,
cameraTopic: cameraTopic,
roadTopic: roadTopic,
}
}
func (r *RoadPart) Start() error {
2021-10-12 21:15:05 +00:00
log := zap.S()
2020-01-04 13:10:36 +00:00
registerCallBacks(r)
var frame = frameToProcess{}
defer func() {
if err := frame.Close(); err != nil {
log.Errorf("unable to close msg: %v", err)
}
}()
for {
select {
case f := <-r.frameChan:
log.Debug("new msg")
oldFrame := frame
frame = f
if err := oldFrame.Close(); err != nil {
log.Errorf("unable to close msg: %v", err)
}
2021-10-12 21:05:10 +00:00
log.Debug("process msg")
go r.processFrame(&frame)
2020-01-04 13:10:36 +00:00
case <-r.cancel:
log.Infof("Stop service")
return nil
}
}
}
var registerCallBacks = func(r *RoadPart) {
err := service.RegisterCallback(r.client, r.cameraTopic, r.OnFrame)
if err != nil {
log.Panicf("unable to register callback to topic %v:%v", r.cameraTopic, err)
}
}
2021-10-12 21:05:10 +00:00
func (r *RoadPart) Stop() {
2020-01-04 13:10:36 +00:00
defer func() {
2021-10-12 21:05:10 +00:00
if err := r.roadDetector.Close(); err != nil {
2021-10-12 21:15:05 +00:00
zap.S().Errorf("unable to close roadDetector: %v", err)
2020-01-04 13:10:36 +00:00
}
}()
2021-10-12 21:05:10 +00:00
close(r.readyForNext)
close(r.cancel)
service.StopService("road", r.client, r.roadTopic)
2020-01-04 13:10:36 +00:00
}
func (r *RoadPart) OnFrame(_ mqtt.Client, msg mqtt.Message) {
var frameMsg events.FrameMessage
err := proto.Unmarshal(msg.Payload(), &frameMsg)
if err != nil {
2021-10-12 21:15:05 +00:00
zap.S().Errorf("unable to unmarshal %T message: %v", frameMsg, err)
2020-01-04 13:10:36 +00:00
return
}
img, err := gocv.IMDecode(frameMsg.GetFrame(), gocv.IMReadUnchanged)
if err != nil {
2021-10-12 21:15:05 +00:00
zap.S().Errorf("unable to decode image: %v", err)
2020-01-04 13:10:36 +00:00
return
}
frame := frameToProcess{
ref: frameMsg.GetId(),
Mat: img,
}
r.frameChan <- frame
}
type frameToProcess struct {
ref *events.FrameRef
gocv.Mat
}
func (r *RoadPart) processFrame(frame *frameToProcess) {
img := frame.Mat
imgGray := gocv.NewMatWithSize(img.Rows(), img.Cols(), gocv.MatTypeCV8UC1)
defer func() {
if err := imgGray.Close(); err != nil {
2021-10-12 21:15:05 +00:00
zap.S().Warnf("unable to close Mat resource: %v", err)
2020-01-04 13:10:36 +00:00
}
}()
gocv.CvtColor(img, &imgGray, gocv.ColorRGBToGray)
road := r.roadDetector.DetectRoadContour(&imgGray, r.horizon)
2021-10-12 21:05:10 +00:00
defer road.Close()
2020-01-04 13:10:36 +00:00
ellipse := r.roadDetector.ComputeEllipsis(road)
2021-10-12 21:05:10 +00:00
cntr := make([]*events.Point, 0, road.Size())
2022-01-03 18:05:47 +00:00
for i := 0; i < road.Size(); i++ {
2021-10-12 21:05:10 +00:00
pt := road.At(i)
2020-01-04 13:10:36 +00:00
cntr = append(cntr, &events.Point{X: int32(pt.X), Y: int32(pt.Y)})
}
msg := events.RoadMessage{
Contour: cntr,
Ellipse: ellipse,
FrameRef: frame.ref,
}
payload, err := proto.Marshal(&msg)
if err != nil {
2021-10-12 21:15:05 +00:00
zap.S().Errorf("unable to marshal %T to protobuf: %err", msg, err)
2020-01-04 13:10:36 +00:00
return
}
publish(r.client, r.roadTopic, &payload)
}
var publish = func(client mqtt.Client, topic string, payload *[]byte) {
client.Publish(topic, 0, false, *payload)
}