First implementation

This commit is contained in:
2019-12-19 00:08:07 +01:00
parent 8eee198344
commit 5e45401858
130 changed files with 20421 additions and 0 deletions

81
camera/camera.go Normal file
View File

@ -0,0 +1,81 @@
package camera
import (
"github.com/cyrilix/robocar-base/mqttdevice"
"gocv.io/x/gocv"
"io"
"log"
"sync"
"time"
)
type VideoSource interface {
Read(m *gocv.Mat) bool
io.Closer
}
type OpencvCameraPart struct {
vc VideoSource
pub mqttdevice.Publisher
topic string
publishFrequency int
muImgBuffered sync.Mutex
imgBuffered *gocv.Mat
}
func New(topic string, publisher mqttdevice.Publisher, publishFrequency int, videoProperties map[gocv.VideoCaptureProperties]float64) *OpencvCameraPart {
log.Printf("Run camera part")
vc, err := gocv.OpenVideoCapture(0)
if err != nil {
log.Fatalf("unable to open video device: %v", err)
}
for k, v := range videoProperties {
vc.Set(k, v)
}
img := gocv.NewMat()
o := OpencvCameraPart{
vc: vc,
pub: publisher,
topic: topic,
publishFrequency: publishFrequency,
imgBuffered: &img,
}
return &o
}
func (o *OpencvCameraPart) Start() error {
log.Printf("start camera")
ticker := time.NewTicker(1 * time.Second / time.Duration(o.publishFrequency))
defer ticker.Stop()
for {
go o.publishFrame()
<-ticker.C
}
}
func (o *OpencvCameraPart) Stop() {
log.Print("close video device")
if err := o.vc.Close(); err != nil {
log.Printf("unexpected error while VideoCapture is closed: %v", err)
}
if err := o.imgBuffered.Close(); err != nil {
log.Printf("unexpected error while VideoCapture is closed: %v", err)
}
}
func (o *OpencvCameraPart) publishFrame() {
o.muImgBuffered.Lock()
defer o.muImgBuffered.Unlock()
o.vc.Read(o.imgBuffered)
img, err := gocv.IMEncode(gocv.JPEGFileExt, *o.imgBuffered)
if err != nil {
log.Printf("unable to convert image to jpeg: %v", err)
return
}
o.pub.Publish(o.topic, img)
}

57
camera/camera_test.go Normal file
View File

@ -0,0 +1,57 @@
package camera
import (
"bytes"
"github.com/cyrilix/robocar-base/testtools"
"gocv.io/x/gocv"
"image/jpeg"
"io"
"log"
"testing"
"time"
)
type fakeVideoSource struct {
io.Closer
}
func (f fakeVideoSource) Read(dest *gocv.Mat) bool {
img := gocv.IMRead("testdata/img.jpg", gocv.IMReadUnchanged)
if img.Total() == 0 {
log.Print("image read is empty")
return false
}
img.CopyTo(dest)
return true
}
func TestOpencvCameraPart(t *testing.T) {
p := testtools.NewFakePublisher()
const topic = "topic/test/camera"
imgBuffer := gocv.NewMat()
part := OpencvCameraPart{
vc: fakeVideoSource{},
pub: p,
topic: topic,
publishFrequency: 1000,
imgBuffered: &imgBuffer,
}
go part.Start()
time.Sleep(1 * time.Millisecond)
img := p.PublishedEvent(topic)
if img == nil {
t.Fatalf("event %s has not been published", topic)
}
content, err := img.ByteSliceValue()
if err != nil {
t.Errorf("unexpected error: %v", err)
}
_, err = jpeg.Decode(bytes.NewReader(content))
if err != nil {
t.Errorf("image published can't be decoded: %v", err)
}
}

BIN
camera/testdata/img.jpg vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB