robocar-camera/pkg/camera/camera.go

141 lines
3.3 KiB
Go
Raw Normal View History

2019-12-18 23:08:07 +00:00
package camera
import (
"fmt"
"github.com/cyrilix/robocar-protobuf/go/events"
mqtt "github.com/eclipse/paho.mqtt.golang"
"github.com/golang/protobuf/ptypes/timestamp"
2021-10-12 16:26:57 +00:00
"go.uber.org/zap"
2019-12-18 23:08:07 +00:00
"gocv.io/x/gocv"
2022-01-03 18:21:35 +00:00
"google.golang.org/protobuf/proto"
"image"
2019-12-18 23:08:07 +00:00
"io"
"sync"
"time"
)
type VideoSource interface {
Read(m *gocv.Mat) bool
io.Closer
}
type OpencvCameraPart struct {
2022-01-03 18:21:35 +00:00
client mqtt.Client
vc VideoSource
topic string
topicRoi string
2019-12-18 23:08:07 +00:00
publishFrequency int
muImgBuffered sync.Mutex
imgBuffered *gocv.Mat
2022-01-03 18:21:35 +00:00
horizon int
cancel chan interface{}
2019-12-18 23:08:07 +00:00
}
func New(client mqtt.Client, topic string, topicRoi string, publishFrequency int,
videoProperties map[gocv.VideoCaptureProperties]float64, horizon int) *OpencvCameraPart {
2021-10-12 16:26:57 +00:00
zap.S().Info("run camera part")
2019-12-18 23:08:07 +00:00
vc, err := gocv.OpenVideoCapture(0)
if err != nil {
2021-10-12 16:26:57 +00:00
zap.S().Fatalf("unable to open video device: %v", err)
2019-12-18 23:08:07 +00:00
}
for k, v := range videoProperties {
vc.Set(k, v)
}
img := gocv.NewMat()
o := OpencvCameraPart{
client: client,
2019-12-18 23:08:07 +00:00
vc: vc,
topic: topic,
2022-01-03 18:21:35 +00:00
topicRoi: topicRoi,
2019-12-18 23:08:07 +00:00
publishFrequency: publishFrequency,
imgBuffered: &img,
}
return &o
}
func (o *OpencvCameraPart) Start() error {
2021-10-12 16:26:57 +00:00
zap.S().Info("start camera")
o.cancel = make(chan interface{})
2019-12-18 23:08:07 +00:00
ticker := time.NewTicker(1 * time.Second / time.Duration(o.publishFrequency))
defer ticker.Stop()
for {
select {
case tickerTime := <-ticker.C:
o.publishFrames(tickerTime)
case <-o.cancel:
return nil
}
2019-12-18 23:08:07 +00:00
}
}
func (o *OpencvCameraPart) Stop() {
2021-10-12 16:26:57 +00:00
zap.S().Info("close video device")
close(o.cancel)
2019-12-18 23:08:07 +00:00
if err := o.vc.Close(); err != nil {
2021-10-12 16:26:57 +00:00
zap.S().Errorf("unexpected error while VideoCapture is closed: %v", err)
2019-12-18 23:08:07 +00:00
}
if err := o.imgBuffered.Close(); err != nil {
2021-10-12 16:26:57 +00:00
zap.S().Errorf("unexpected error while VideoCapture is closed: %v", err)
2019-12-18 23:08:07 +00:00
}
}
func (o *OpencvCameraPart) publishFrames(tickerTime time.Time) {
2019-12-18 23:08:07 +00:00
o.muImgBuffered.Lock()
defer o.muImgBuffered.Unlock()
o.vc.Read(o.imgBuffered)
// Publish raw image
o.publishFrame(tickerTime, o.topic, o.imgBuffered)
if o.horizon == 0 {
return
}
// Region of interest
roi := o.imgBuffered.Region(image.Rect(0, o.horizon, o.imgBuffered.Cols(), o.imgBuffered.Rows()))
defer roi.Close()
o.publishFrame(tickerTime, o.topicRoi, &roi)
}
func (o *OpencvCameraPart) publishFrame(tickerTime time.Time, topic string, frame *gocv.Mat) {
img, err := gocv.IMEncode(gocv.JPEGFileExt, *frame)
2019-12-18 23:08:07 +00:00
if err != nil {
zap.S().With("topic", topic).Errorf("unable to convert image to jpeg: %v", err)
2019-12-18 23:08:07 +00:00
return
}
2022-01-03 18:21:35 +00:00
defer img.Close()
2019-12-18 23:08:07 +00:00
msg := &events.FrameMessage{
Id: &events.FrameRef{
Name: "camera",
2020-02-15 17:00:50 +00:00
Id: fmt.Sprintf("%d%03d", tickerTime.Unix(), tickerTime.Nanosecond()/1000/1000),
CreatedAt: &timestamp.Timestamp{
2020-01-28 22:30:38 +00:00
Seconds: tickerTime.Unix(),
Nanos: int32(tickerTime.Nanosecond()),
},
},
2022-01-03 18:21:35 +00:00
Frame: img.GetBytes(),
}
payload, err := proto.Marshal(msg)
if err != nil {
2021-10-12 16:26:57 +00:00
zap.S().Errorf("unable to marshal protobuf message: %v", err)
}
publish(o.client, topic, &payload)
}
var publish = func(client mqtt.Client, topic string, payload *[]byte) {
token := client.Publish(topic, 0, false, *payload)
token.WaitTimeout(10 * time.Millisecond)
if err := token.Error(); err != nil {
2021-10-12 16:26:57 +00:00
zap.S().Errorf("unable to publish frame: %v", err)
}
2019-12-18 23:08:07 +00:00
}