Elsaの技術日記(徒然なるままに)

主に自分で作ったアプリとかの報告・日記を記載

MENU

go言語でvl53l0xを使ってみる

以前、vl53l0xで距離測定を行いました。
elsammit-beginnerblg.hatenablog.com

どうせなら、go言語でも実施してみたいな!!と思い調べてみました!!
せっかく調べたのでまとめておこうと思います!!



■使用環境

用いたデバイスは下記です。
・ラズパイ4
・測距センサ

測距センサですが、こちらを利用。

VL53L0Xレーザー測距センサーToF測距飛行時間測距センサーモジュール

新品価格
¥1,450から
(2020/12/12 22:38時点)

VL53L0Xを用いた構成は下記となります。
f:id:Elsammit:20200906172530p:plain

■ラズパイへのI2C設定

ラズパイへのI2C設定は以前こちらにまとめましたので必要に応じて確認ください。
elsammit-beginnerblg.hatenablog.com

■Go言語でのvl53l0x事前準備

Go言語でvl53l0xを用いるにあたり、すでにライブラリが用意されております!!
ライブラリをインストールするにあたり、こちらのコマンドを実行。

go get -u github.com/d2r2/go-vl53l0x

エラーメッセージが表示されなければインストールは完了です!!
設定は以上になります!!すでにライブラリが用意されているのでセッティングが楽ですね!!

■Go言語でvl53l0xを用いた距離測定

ではセッティングが完了しましたので、さっそく距離測定を行うコードを書いていきたいと思います!!
と言ってもすでに本ライブラリを作成した方がサンプルを展開されておりますので、そちらを流用!!

package vl53l0x

import (
	"fyne.io/fyne/widget"
	i2c "github.com/d2r2/go-i2c"
	vl53l0x "github.com/d2r2/go-vl53l0x"
	"log"
	"strconv"
	"time"
)

func main() {
	i2c, err := i2c.NewI2C(0x29, 1)
	if err != nil {
		log.Fatal(err)
	}
	defer i2c.Close()

	sensor := vl53l0x.NewVl53l0x()
	err = sensor.Reset(i2c)
	if err != nil {
		log.Fatal(err)
	}
	err = sensor.Init(i2c)
	if err != nil {
		log.Fatal(err)
	}
	for {
		rng, err := sensor.ReadRangeSingleMillimeters(i2c)
		if err != nil {
			log.Fatal(err)
		}
		log.Printf("Measured range = %v mm", rng)
		time.Sleep(time.Second)
	}
}

こちらのコードですが、

i2c, err := i2c.NewI2C(0x29, 1)

でI2Cのデバイス番号(0x29)とI2Cのデバイスドライバ番号(1)を設定します。
それぞれ、
バイス番号

i2cdetect -y 1

デバイスドライバ番号

ls /dev/i2c*

で確認できます。

そしてこちらのコードでセンサを定義するのと同時にI2Cの初期化を行います。

sensor := vl53l0x.NewVl53l0x()
err = sensor.Reset(i2c)
err = sensor.Init(i2c)

最後に、

	for {
		rng, err := sensor.ReadRangeSingleMillimeters(i2c)
		if err != nil {
			log.Fatal(err)
		}
		log.Printf("Measured range = %v mm", rng)
		time.Sleep(time.Second)
	}

で1秒ごとに距離の測定を行います。
距離はミリメートルで取得できます。

■困っていること

デバッグログがかなり出力されてしまうので他のログが醜くなっているのが厄介だな、と感じております。
無効方法が分かっていないのでもう少し調べてみようと思います!!

■最後に

go言語でもvl53l0xが制御できるようになりました!!
最近デバイス制御系に偏ってしまっている気がするので、改めてWeb系をやっていこうかな?と思います。



Go言語 GUIアプリ Fyneへの動画表示

先日Fyneを使用して簡単なGUIアプリを作成しました。
elsammit-beginnerblg.hatenablog.com

今回はFyneを利用して動画を表示・再生させるアプリを作成していこうと思います!!



■環境

・OS:Ubuntu20.04(virtualBox上)
 ※すでにFyneがインストールされていることを前提にします。

■Fyneへの画像表示

動画表示・再生を行う前にまずは画像の表示を行っていきます。
コードはこんな感じ。

package main

import (
	"fmt"
	"fyne.io/fyne/app"
	"fyne.io/fyne/canvas"
	"fyne.io/fyne/widget"
	"gocv.io/x/gocv"
	"image"
)

func main() {
	Flg = false
	fileName := "ファイルパス"
	img := gocv.IMRead(fileName, -1)
	gocv.Resize(img, &img, image.Point{250, 250}, 0, 0, gocv.InterpolationDefault)

	imgD, _ := img.ToImage()

	myApp := app.New()
	w := myApp.NewWindow("Image")

	ShowImg := canvas.NewImageFromImage(imgD)
	ShowImg.FillMode = canvas.ImageFillOriginal

	label := widget.NewLabel("Show image")

	w.SetContent(widget.NewVBox(
		ShowImg,
		label,
	))

	w.ShowAndRun()
}

やっていることは、
opencvで画像データを読み出す。

	img := gocv.IMRead(fileName, -1)
	gocv.Resize(img, &img, image.Point{250, 250}, 0, 0, gocv.InterpolationDefault)

画像表示用画像イメージに変換。

        imgD, _ := img.ToImage()

用意したcanvasの上に読み出した画像データをセット。

	ShowImg := canvas.NewImageFromImage(imgD)
	ShowImg.FillMode = canvas.ImageFillOriginal

最後にGUIとしてレイアウトを決めて、

	w.SetContent(widget.NewVBox(
		ShowImg,
		label,
	))

画面表示、

	w.ShowAndRun()

になります。

今回画像をこちらとした場合、
f:id:Elsammit:20201212194817j:plain

先ほどのコードを実行するとこちらのアプリが表示されます。
f:id:Elsammit:20201212195007p:plain

■動画表示

では本題の動画を表示させます。
全体のコードはこちらになります。

package main

import (
	"fyne.io/fyne/app"
	"fyne.io/fyne/canvas"
	"fyne.io/fyne/widget"
	"gocv.io/x/gocv"
	"image"
	"time"
)

func MakeMovie(ShowImg *canvas.Image) {
	movie, _ := gocv.OpenVideoCapture("再生させる動画パス")
	img := gocv.NewMat()
	imgDD, _ := img.ToImage()
	for {
		movie.Read(&img)
		gocv.Resize(img, &img, image.Point{250, 250}, 0, 0, gocv.InterpolationDefault)
		imgDD, _ = img.ToImage()
		ShowImg.Image = imgDD
		canvas.Refresh(ShowImg)
		time.Sleep(time.Millisecond * 33)
	}
}

func main() {
	fileName := "lena.jpg"
	img := gocv.IMRead(fileName, -1)
	gocv.Resize(img, &img, image.Point{250, 250}, 0, 0, gocv.InterpolationDefault)

	imgD, _ := img.ToImage()

	myApp := app.New()
	w := myApp.NewWindow("Image")

	ShowImg := canvas.NewImageFromImage(imgD)
	ShowImg.FillMode = canvas.ImageFillOriginal

	label := widget.NewLabel("Show Movie")
	go MakeMovie(ShowImg)

	w.SetContent(widget.NewVBox(
		ShowImg,
		label,
	))
	w.ShowAndRun()
}

先ほどの画像表示と異なる点は、

func MakeMovie(ShowImg *canvas.Image) {
	movie, _ := gocv.OpenVideoCapture("再生させる動画パス")
	img := gocv.NewMat()
	imgDD, _ := img.ToImage()
	for {
		movie.Read(&img)
		gocv.Resize(img, &img, image.Point{250, 250}, 0, 0, gocv.InterpolationDefault)
		imgDD, _ = img.ToImage()
		ShowImg.Image = imgDD
		canvas.Refresh(ShowImg)
		time.Sleep(time.Millisecond * 33)
	}
}

を追加して、

go MakeMovie(ShowImg)

により並列処理を行っている点です。

MakeMovie関数ですが、
引数に用意した*canvas.Imageを渡し、
動画の1フレーム毎に取得、canvas.Imageにセットする
処理を行っております。

先ほどの画像と同様、canvasへセットするために読みとったフレーム画像は

imgDD, _ = img.ToImage()

より変換を行っております。

最後に!!
毎回フレーム画像をリフレッシュしないと反映されないので必ずこちらの関数を用いてください。

canvas.Refresh(ShowImg)

では、実際にこちらのコードを用いて、動画を再生してみます!!
実行するとこんな感じで再生されます。
f:id:Elsammit:20201212200800g:plain

■再生・停止ボタン追加(おまけ)

おまけとして、再生・停止ボタンを用意して動画の停止・再開の機能を追加したいと思います。
コードはこちらになります。

package main

import (
	"fmt"
	"fyne.io/fyne/app"
	"fyne.io/fyne/canvas"
	"fyne.io/fyne/widget"
	"gocv.io/x/gocv"
	"image"
	"time"
)

var Flg bool

func MakeMovie(ShowImg *canvas.Image) {
	Movie, _ := gocv.OpenVideoCapture("./Underwater - 37712.mp4")
	img := gocv.NewMat()
	imgDD, _ := img.ToImage()
	for {
		if Flg == true {
			Movie.Read(&img)
			gocv.Resize(img, &img, image.Point{250, 250}, 0, 0, gocv.InterpolationDefault)
			imgDD, _ = img.ToImage()
			ShowImg.Image = imgDD
			canvas.Refresh(ShowImg)
			time.Sleep(time.Millisecond * 33)
		} else {
			time.Sleep(time.Second)
		}
	}
}

func main() {
	Flg = false
	fileName := "lena.jpg"
	img := gocv.IMRead(fileName, -1)
	gocv.Resize(img, &img, image.Point{250, 250}, 0, 0, gocv.InterpolationDefault)

	imgD, _ := img.ToImage()

	myApp := app.New()
	w := myApp.NewWindow("Image")

	ShowImg := canvas.NewImageFromImage(imgD)
	ShowImg.FillMode = canvas.ImageFillOriginal

	label := widget.NewLabel("Show Movie")
	go MakeMovie(ShowImg)
	var button *widget.Button
	button = widget.NewButton("Start", func() {
		label.SetText("Welcome")
		fmt.Println("push Button")

		if Flg == true {
			button.SetText("Start")
			Flg = false
		} else {
			button.SetText("Stop")
			Flg = true
		}
	})

	w.SetContent(widget.NewVBox(
		ShowImg,
		label,
		button,
	))

	w.ShowAndRun()
}

追加しているのはStart/Stopフラグのみ(のはず)。

こちらを実行するとこちらのようになります!!
f:id:Elsammit:20201212201539g:plain

■最後に

今回はfyneを用いてGUIアプリ上に動画を表示させ、最終的に動画再生・停止までが行えるようにしました。
先ほどの動画パスをデバイス番号(0,1,..)に置き換えればカメラキャプチャ動画の再生も行えるようになります。



raspberryPiでの仮想ビデオデバイス(/dev/video)の作成

今回は仮想ビデオデバイスを作成して作成したビデオデバイス経由で動画データのやり取りを行っていきます。
動画データのやり取りに用いるのはgstreamerです。
gstreamerについてはこちらにまとめておりますのでぜひ!!
elsammit-beginnerblg.hatenablog.com
elsammit-beginnerblg.hatenablog.com


■環境

今回の環境はこちらです。
・デバイス:raspberry Pi4
・OS:
・カメラ:UCAM-C520FBBK

■事前準備

仮想ビデオデバイス作成にあたり、v4l2loopを用います。
v4l2loopをインストールするために、

sudo apt-get install v4l2loopback-dkms

を実行。

■仮想ビデオデバイス作成

仮想ビデオデバイスを作成するコマンドは、

sudo modprobe v4l2loopback

です。
こちらを実行してから、

ls /dev/video*

を実行するとビデオドライバが1つ増えていることが確認できます。

さらに、複数ビデオデバイスを作成する場合には、

sudo modprobe v4l2loopback devices=デバイス数

となります。

■仮想デバイスを用いた動画表示

では実際に仮想ビデオデバイス経由で動画の再生を行ってみます!!
まずは作成したビデオデバイスへの動画データ書き込みです。
仮想ビデオデバイスがvideo2の場合、コマンドはこちらのようになります。

gst-launch-1.0 -v v4l2src device=/dev/video0 ! videoconvert ! v4l2sink device=/dev/video2 sync=false
device=/dev/video2

を作成したビデオデバイスに置き換えればOKです。

では次に仮想ビデオデバイスからの読み出しです。
コマンドはこちらのようになります。

gst-launch-1.0 -v v4l2src device=/dev/video2 ! videoconvert ! autovideosink

先ほどの動画書き込み側のコマンドを実行した後に、読み出し用のコマンドを実行すれば、
カメラからのキャプチャ動画が表示されるかと思います。

■go言語で仮想ビデオデバイスから読み出してみる

次にgo言語を用いて、仮想ビデオデバイスから動画データを読み出し、表示をしてみます。
コードはこちらです。

package main

import (
	"gocv.io/x/gocv"
	"image"
)

func main() {
	webcam, _ := gocv.OpenVideoCapture("v4l2src device=/dev/video2 ! videoconvert ! appsink")
	window := gocv.NewWindow("hello")
	img := gocv.NewMat()

	for {
		webcam.Read(&img)
		gocv.Resize(img, &img, image.Point{640, 480}, 0, 0, gocv.InterpolationDefault)
		window.IMShow(img)
		window.WaitKey(1)
	}
}

gocvを用いて、仮想ビデオデバイスから画像データを読み出し、
IMShowで表示しております。

gocv.OpenVideoCapture("v4l2src device=/dev/video2 ! videoconvert ! appsink")

へ与えるビデオデバイスを変更させれば好きなビデオデバイスからの動画読み出しが可能です。

■最後に

今回は仮想ビデオデバイスの作成方法についてまとめてみました。
こちらを用いれば、デバイスドライバ経由での動画データのやり取りが出来ますね!!

自分で作るのはしんどいな。。。と思っていたので、この方法が知れたのはありがたかった!!



go言語 GUIアプリ Fyne導入

今回はgo言語でGUIアプリの作成を行っていきます。

go言語のGUIアプリですが複数種類あります。
が、QtやGtkは使ったことがあったので出来れば別の方法が良いな!!
と思い、調べてみたら見つけたので早速使用してみることにしました。



■動作環境

・OS:Ubuntu20.04(VirtualBox 仮想環境)
・go version:1.13.08

go versionが1.9以下ですと、Fyneはインストールできるのですが、
コードを作成してビルド・実行を行うと、

../go/src/fyne.io/fyne/storage/uri.go:29:10: undefined: strings.ReplaceAll
../go/src/fyne.io/fyne/storage/uri.go:30:10: undefined: strings.ReplaceAll

といったエラーが発生してしまいます。
必ず1.10以上(出来る限り最新の)go言語をご利用ください。

■Fyneインストール

ではFyneをインストールしていきます。
こちらを実行。

go get fyne.io/fyne

これでインストール完了!!

では動作確認!!
動作確認用のソースコードをダウンロード。

go get fyne.io/fyne/cmd/fyne_demo/

そして、fyne_demo配下に格納されているmain.goを実行。

go run main.go


こちらのようなGUIアプリが表示されればFyneのインストールは成功です。
f:id:Elsammit:20201210223215p:plain

■簡単なコード作成

では簡単なサンプルコードを作成し、実行してみます。
まずはコードから。

package main

import (
	"fyne.io/fyne/app"
	"fyne.io/fyne/widget"
)

func main() {
	a := app.New()
	w := a.NewWindow("Hello")
	hello := widget.NewLabel("Hello Fyne")
	w.SetContent(
		widget.NewHBox(
			hello,
			widget.NewButton("Hi", func() {
				hello.SetText("Welcome")
			}),
		),
	)
	w.ShowAndRun()
}

こちらはfyneが公式で公開しているサンプルコードを写経したものですw

a := app.New()
w := a.NewWindow("Hello")

でアプリやウィンドウ(表示画面)を定義。

そして、

	w.SetContent(
		widget.NewVBox(
			hello,
			widget.NewButton("Hi", func() {
				hello.SetText("Welcome")
			}),
		),
	)

で表示する形状を定義。
最後に、

w.ShowAndRun()

GUIアプリを実行。

といった形になります。
結構直感的に作成できるのが良いですね!!

こちらを実行すると、
f:id:Elsammit:20201210223940p:plain
が表示されます。
そして、Hiと記載されたボタンを押下すると、
f:id:Elsammit:20201210224044p:plain
というようにLabelの文字が変化します。

この

widget.NewVBox(

widget.NewHBox(

に変更すると、
f:id:Elsammit:20201210224653p:plain
というように横に並びます。

■簡単なコード作成2

今後はこちらのコードを作成。

package main

import (
	"fyne.io/fyne/app"
	"fyne.io/fyne/widget"
)

func main() {
	a := app.New()
	w := a.NewWindow("Hello")
	hello_1 := widget.NewLabel("Hello Fyne")
	hello_2 := widget.NewLabel("Hello world")
	w.SetContent(
		widget.NewHBox(
			widget.NewVBox(
				hello_1,
				widget.NewButton("No.1", func() {
					hello_1.SetText("Welcome")
				}),
			),
			widget.NewVBox(
				hello_2,
				widget.NewButton("No.2", func() {
					hello_2.SetText("AAA")
				}),
			),
		),
	)
	w.ShowAndRun()
}

こちらを実行すると、
f:id:Elsammit:20201210225511g:plain
といったアプリが作成できます。

ラベル+ボタンを縦に並べ、

			widget.NewVBox(
				hello_1,
				widget.NewButton("No.1", func() {
					hello_1.SetText("Welcome")
				}),
			),

それぞれを、

widget.NewHBox(

によって横に並べております。

■最後に

今回はfyneについて使用してみました。
結構感覚的に使用できたので、結構簡単に使えるライブラリだな!!と感じました。
使っていってみようかしら?



画像データをバイト(文字列)データに変換

今回は画像データをバイト(文字列)データに変換する方法についてまとめておこうと思います!!


■環境

コードはpythonで書いていきます。
詳細はこちら。

・OS Windows10
python version:3.4.7

■画像データをバイト列に変換

変換のコードはこちらになります。

import os
import io
from PIL import Image
import numpy as np

class ImgByteChange:
    def __init__(self):
        pass
    def ImageToByte(self,Img):
        tmpimg = Image.open(Img)
        with io.BytesIO() as output:
            tmpimg.save(output,format="PNG")
            ImgToByte = output.getvalue()
            return ImgToByte
    
imgByteChange = ImgByteChange()
test = imgByteChange.ImageToByte(画像ファイルパス)

重要なのは、

    def ImageToByte(self,Img):
        tmpimg = Image.open(Img)
        with io.BytesIO() as output:
            tmpimg.save(output,format="PNG")
            ImgToByte = output.getvalue()

です。
イメージファイルをオープンしてから、

        with io.BytesIO() as output:
            tmpimg.save(output,format="PNG")
            ImgToByte = output.getvalue()

にて開いた画像に対してバイト列に変換。変数に格納しております。


こちらの画像に対して
f:id:Elsammit:20201208230426p:plain

コードを実行すると、

b'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x96\x00\x00\x00\x96\x08\x00\x00\x00\x00\x19j.>\x00\x00\x00\xa7IDATx\x9c\xed\xd9A\n\x021\x10\x00\xc1(\xfb\xff/\xeb\x0b\xe6\xd0\x8b\xe8\x08U\xd7\x10\xd2\xccm\xc89\x00\x00\x00\xb0\xdec<y\xfd\xf2\xf5\xe7\x17\x1e\xbfAV!\xab\x90U\xc8*d\x15\xb2\nY\x85\xacBV!\xab\x90U,\xcd\xba\xfa\x95y\xe3\x9d\xf4Mx\xe9\xb4d\x15\xb2\nY\x85\xacBV!\xab\x90U\xc8*d\x15\xb2\nY\x85\xacBV!\xab\x90U\xc8*d\x15\xb2\nY\x85\xacBV!\xab\x90U\xc8*\xe6\xdf\xd7\xfe\xc9\xfaAK\xa7%\xab\x90U\xc8*d\x15\xb2\nY\x85\xacBV!\xab\x90U\xc8*\x96f\x01\x00\x00\xc0\x1fx\x03\xe9R\x02\xcdQ\x93\xdcP\x00\x00\x00\x00IEND\xaeB`\x82'

というようにバイト列(文字列)が得られます。

■バイト列から画像イメージに変換

今度は逆にバイト列から画像イメージに変換するコードを記載します。
そのコードはこちら。

import os
import io
from PIL import Image
import numpy as np

class ImgByteChange:
    def __init__(self):
        pass
    
    def ByteToImage(self, str):
        ByteToImg = Image.open(io.BytesIO(str))
        return ByteToImg     

imgByteChange = ImgByteChange()
img = imgByteChange.ByteToImage(バイト列)

こちらが今回の重要点。

 Image.open(io.BytesIO(str))

こちらのコードで文字列から画像イメージに変換しています。

バイト列を変数に与えるのは大変なので、
こちらのコードを用いて、画像⇒文字列⇒画像の順に変換して画像を見比べてみたいと思います。

import os
import cv2
import io
from PIL import Image
import numpy as np

class ImgByteChange:
    def __init__(self):
        pass
    def ImageToByte(self,Img):
        tmpimg = Image.open(Img)
        with io.BytesIO() as output:
            tmpimg.save(output,format="PNG")
            ImgToByte = output.getvalue()
            return ImgToByte
    
    def ByteToImage(self, str):
        ByteToImg = Image.open(io.BytesIO(str))
        return ByteToImg     

imgByteChange = ImgByteChange()
test = imgByteChange.ImageToByte(入力画像)
img = imgByteChange.ByteToImage(test)
img.save('出力画像)

今度はこちらの画像を入力。
f:id:Elsammit:20201208231252p:plain

結果はこちらです。
f:id:Elsammit:20201208231306p:plain

同じ画像が得られました!!
良かった!!

■最後に

今回は画像データのバイト列(文字列データ変換とバイト列データを画像データに変換する方法についてまとめました。
実はこちらを用いて、実行ファイル同士で共有メモリ通信的なことをしてデータのやり取りしようかな?と思っていたのですが、
別の方法が分かったのでそちらで画像データのやり取りをする方法をまとめたいと思います!!

この変換方法も後で後で何かに使えるかな?


go言語でカメラ映像配信を受信してみる

前回、gstreamingを用いたrtpでのカメラ映像の配信・受信を行いました。
ですが、前回の方法ですとコマンドベースでの動作でした。
elsammit-beginnerblg.hatenablog.com

今度はgo言語でrtpで送信されたデータを受信してみたいと思います!!
go言語でgstreamingを実施するにあたって、gocv用います。
gocvのインストール手順はこちらを参考ください。
elsammit-beginnerblg.hatenablog.com



■環境

・OS:Ubuntu16.04
・Go言語バージョン:go1.11.5 linux/amd64
・gocvバージョン:0.24.0

■事前準備

gocvを用いるにあたり、デフォルトだとgstreamerがOFF(無効)になっているようです。
このため、gstreamerを有効にする必要があり、再度ビルドしなおす必要があります。

まずはgstreamerを有効にするために設定を変更します。
gocv.io/x/gocv配下に格納された"travis_build_opencv.sh"を変更・追加します。

cmake -D WITH_IPP=${GRAPHICAL} \
      -D WITH_OPENGL=${GRAPHICAL} \
      -D WITH_QT=${GRAPHICAL} \
      -D BUILD_EXAMPLES=OFF \
      -D BUILD_TESTS=OFF \
      -D BUILD_PERF_TESTS=OFF  \
      -D BUILD_opencv_java=OFF \
      -D BUILD_opencv_python=OFF \
      -D BUILD_opencv_python2=OFF \
      -D BUILD_opencv_python3=OFF \
      -D OPENCV_GENERATE_PKGCONFIG=ON \
      -D CMAKE_INSTALL_PREFIX=$HOME/usr \
      -D OPENCV_ENABLE_NONFREE=ON \
      -D WITH_FFMPEG=OFF \        ←OFFに変更.
      -D WITH_GTK=ON \        ←追加.
      -D WITH_GSTREAMER=ON \  ←追加.
      -D OPENCV_EXTRA_MODULES_PATH=../../opencv_contrib-${OPENCV_VERSION}/modules ..
-D WITH_FFMPEG=OFF

は不要かもしれませんが、、、
どうやら、FFMPEGとGSTREAMERが両方ONになっていると動作不安定になるとのことで念のため。

修正変更したら、

sudo make install

を実行してgocvのビルドとインストールを行います。

インストール成功したら動作確認!!

■動作確認

では動作確認を行います。
まずはこちらのコードを実行。

package main

import (
	"fmt"
	"gocv.io/x/gocv"
)

func main() {
	test := "videotestsrc ! videoconvert ! appsink"
	webcam, _ := gocv.OpenVideoCapture(test)
	window := gocv.NewWindow("Hello")
	img := gocv.NewMat()

	for {
		if ok := webcam.Read(&img); !ok {
			fmt.Printf("cannot read device \n")
			return
		}
		if img.Empty() {
			continue
		}
		window.IMShow(img)
		if window.WaitKey(1) >= 0 {
			break
		}
	}
}

こちらの映像が表示されればOKです。
f:id:Elsammit:20201206221940g:plain

こちらのコードですが、OpenVideoCaptureに与えるデータを

test := "videotestsrc ! videoconvert ! appsink"

としており、gstreamerで用意?されたテスト動画をinputとして与えています。
後は、

 webcam.Read(&img)

でフレーム映像を取得、

window.IMShow(img)

で映像表示しております。

この

test := "videotestsrc ! videoconvert ! appsink"

を、

test := "v4l2src! videoconvert ! appsink"

に置き換えればカメラ映像を表示させることが出来ます。

■rtp配信動画受信

セットアップが出来たので、本題のrtp配信動画を扱っていきます。
まずは、送信されてきた動画データの受信です。
まずはコードから。

package main

import (
	"fmt"
	"gocv.io/x/gocv"
)

func main() {
	test := "udpsrc port=5005 ! application/x-rtp,media=video,encoding-name=H264 ! queue ! rtph264depay ! avdec_h264 ! videoconvert ! appsink"
	webcam, _ := gocv.OpenVideoCapture(test)
	window := gocv.NewWindow("Hello")
	img := gocv.NewMat()

	for {
		if ok := webcam.Read(&img); !ok {
			fmt.Printf("cannot read device \n")
			return
		}
		if img.Empty() {
			continue
		}
		window.IMShow(img)
		if window.WaitKey(1) >= 0 {
			break
		}
	}
}

先ほどの動作確認とほぼほぼ同じコードで実現できますw。
異なる点は、

test := "udpsrc port=5005 ! application/x-rtp,media=video,encoding-name=H264 ! queue ! rtph264depay ! avdec_h264 ! videoconvert ! appsink"

で、データ受信先を

udpsrc port=5005

に変更し、エンコード

application/x-rtp,media=video,encoding-name=H264 ! queue ! rtph264depay ! avdec_h264 ! videoconvert

としている点です。
前回のrtp受信コマンドで用いたコードをそのまま入力すれば実行できます。

事前に、

gst-launch-1.0 -v videotestsrc ! videoscale ! video/x-raw,width=160,height=120 ! videorate ! video/x-raw,framerate=100/1 ! x264enc ! rtph264pay ! udpsink host=127.0.0.1 port=5005 sync=false

を実行し、先ほどのコードを実行すると、
f:id:Elsammit:20201206221940g:plain
が表示されるかと思います。

■最後に

go言語でgstreamerを用いた映像受信方法についてまとめました。
送信側はただいま勉強中。



gstreamerでrtp経由でストリーミング

今回はgstreamerでrtp(udp)でストリーミングする方法についてまとめておこうと思います!!
コマンド1つで動画配信できるようなので少しまとめておこうと思います!!


■環境

・OS:Ubuntu16.04(VirtualBox上)
・カメラ:UCAM-C520FBBK

エレコム WEBカメラ マイク内蔵 200万画素 高精細ガラスレンズ ブラック UCAM-C520FBBK

新品価格
¥2,300から
(2020/12/5 22:39時点)

カメラですが、ちょっと興味があって別のカメラ買って見ましたww
結構こちらのカメラも写りよかった。

■セッティング

今回gstreamerはインストール済みでしたが、ちょっと足りないライブラリもあったのでインストールします。

sudo apt-get install gstreamer1.0-plugins-ugly
sudo apt-get install gstreamer1.0-libav

■テスト動作確認

ではテスト動画を再生させてみたいと思います!!
こちらを実行してテスト動画確認できます。

gst-launch-1.0 videotestsrc ! videoconvert ! autovideosink

問題がなければこちらの動画が画面上に表示されるかと思います。
f:id:Elsammit:20201205214138g:plain

次にカメラから取得した映像を画面上に表示させてみます。
こちらのコマンドを実行します。

gst-launch-1.0 -v v4l2src  ! videoconvert ! autovideosink

これでカメラから取得した映像が表示されればOKです。

■カメラ映像について

先ほどのコマンドですが、それぞれ
テスト動画:テスト動画を受信 ! エンコード/デコード ! ビデオ表示用ドライバにデータ格納
カメラ動画:カメラからの動画受信 ! エンコード/デコード ! ビデオ表示用ドライバにデータ格納
の意味になっています。

gst-launch-1.0では上記のように、
何等かのデバイスやテストデータから~~srcで取得。
取得したデータをエンコード/デコードして加工。
最後に~~sinkで指定したドライバにデータを格納。
するように指定します。

要するに、
・v4l2src:カメラ映像取得
・videotestsrc :テスト動画取得
・autovideosink:モニタへの動画表示
といった形です。

■gstreamerを用いたrtpストリーミング

まずは配信側です。
こちらのコマンドで配信可能です。

gst-launch-1.0 -v v4l2src ! videoscale ! video/x-raw,width=320,height=240 ! videorate ! video/x-raw,framerate=100/1 ! x264enc ! rtph264pay ! udpsink host=127.0.0.1 port=5005 sync=false

こちらのコマンドの意味ですが、

v4l2src 

でカメラ映像を取得し、

videoscale ! video/x-raw,width=320,height=240 ! videorate ! video/x-raw,framerate=100/1

で映像サイズやフレームレートを指定。

 x264enc ! rtph264pay

で映像をrtp用にデータをエンコード

最後に、

udpsink host=127.0.0.1 port=5005 sync=false

IPアドレスとポート番号を指定してrtp配信用のドライバにデータを格納します。
今回はローカルへの配信としています。

次に配信されているデータを受信します。
こちらのコマンドで実行可能です。

gst-launch-1.0 -v udpsrc port=5005 ! application/x-rtp,media=video,encoding-name=H264 ! queue ! rtph264depay ! avdec_h264 ! videoconverter ! autovideosink

まず、

udpsrc port=5005

で配信された動画を取得。

そして、こちらでH.264形式のフォーマットに変換。

application/x-rtp,media=video,encoding-name=H264 ! queue ! rtph264depay ! avdec_h264 ! videoconverter

最後に、

autovideosink

で映像表示用のドライバにデータを格納。

といった流れになります。

■最後に

今回はgstreamerを用いてコマンドではありますがrtp経由で動画ストリーミングを行いました。
。。。用語間違っていたらすいません。