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

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

MENU

go言語でバーコードリーダー

今回はgo言語でバーコードリーダーを作っていきたいと思います。
pythonで作成している記事を見つけ、これならgo言語でも出来るかも!!と思い試してみました。


■開発環境

ubuntu16.04
go言語バージョン:go1.11.5 linux/amd64

■事前準備

バーコードを読み取るにあたり、zbarを用います。
go言語にはzbarのライブラリが公開されているのでこちらを用いればよいのですが、、、
ただgo getでインストールすると、

fatal error: 'zbar.h' file not found

といったエラーが発生してしまいます。。。

そこで、インストールする前にこちらで事前準備。

sudo apt-get install libzbar-dev

問題なくインストール出来たら、

go get github.com/PeterCxy/gozbar

を実行してお目当てのライブラリをインストールします。

■go言語でバーコード読み取り

では早速読み取りを行っていきます。
下記gihubのscanner_test.goにサンプルがあります。
https://github.com/PeterCxy/gozbar

こちらのサンプルを元に下記のように実装。

package main

import (
	"fmt"
	"github.com/PeterCxy/gozbar"
	"image/png"
	"os"
)

func main() {
	f, err := os.Open("img/barcode.png")
	if err != nil {
		println("Read Error")
		return
	}

	i, _ := png.Decode(f)    // 読み取った画像データをデコード
	img := zbar.FromImage(i) // 画像をzbarで読み取れるように加工.
	s := zbar.NewScanner()
	s.SetConfig(0, zbar.CFG_ENABLE, 1)
	ret := s.Scan(img) // バーコードスキャン実施.
	defer s.Destroy()
	if ret == 1 {
		img.First().Each(func(str string) {
			fmt.Println(str)
		})
	}
}

基本的にコメントの通りですが、

ret := s.Scan(img)

でバーコードを読み取るのですが、
結果が1であれば成功、それ以外は失敗となります。
さらに、読み取り結果は

img.First()

に格納されているとのことですので、

img.First().Each(func(str string) {
	fmt.Println(str)
})

で読み出しております。

に先ほどのgithubのtestdataフォルダにこちらの
f:id:Elsammit:20201201223131p:plain
サンプル画像が入っておりますのでこちらを利用して実行すると、

9876543210128

が出力され、バーコードが読み取れていることが確認できます。

さらにOpenCVと連携させるとこちらのようなコードになります。

package main

import (
	"fmt"
	"github.com/PeterCxy/gozbar"
	"gocv.io/x/gocv"
)

func main() {
	imgA := gocv.IMRead("img/barcode.png", -1)  //ここが先ほどと異なる点.
	i, _ := imgA.ToImage()                                       //ここが先ほどと異なる点.
	img := zbar.FromImage(i)
	s := zbar.NewScanner()
	s.SetConfig(0, zbar.CFG_ENABLE, 1)
	ret := s.Scan(img)
	defer s.Destroy()
	if ret == 1 {
		img.First().Each(func(str string) {
			fmt.Println(str)
		})
	}
}

先ほどのコードと異なる点は、

imgA := gocv.IMRead("img/barcode.png", -1)  //ここが先ほどと異なる点.
i, _ := imgA.ToImage()                                       //ここが先ほどと異なる点.

です。
opencvのimshowで画像を読み取ってから、
mat型からimage型に型変換を行っております。

こちらも先ほどのサンプル画像を指定して実行すると、

9876543210128

が得られます。

■カメラからのバーコード読み取り

先ほどOpenCVを用いて画像からバーコードを読み取りました。
では次にOpenCVにてVideoCaputureし、そのフレーム画像からバーコードの読み取りを実施したいと思います。
コードはこちらです。

package main

import (
	"fmt"
	"github.com/PeterCxy/gozbar"
	"gocv.io/x/gocv"
)

func main() {
	webcam, _ := gocv.OpenVideoCapture(0)
	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
		}
		i, _ := img.ToImage()
		zimg := zbar.FromImage(i)
		s := zbar.NewScanner()
		s.SetConfig(0, zbar.CFG_ENABLE, 1)
		ret := s.Scan(zimg)
		defer s.Destroy()
		if ret == 1 {
			zimg.First().Each(func(str string) {
				fmt.Println(str)
			})
		}
		window.IMShow(img)
		if window.WaitKey(1) >= 0 {
			break
		}
	}
}

基本的には先ほどの画像読み取りと同様に、VideoCaptureで取得したフレーム画像に対して、

i, _ := img.ToImage()
zimg := zbar.FromImage(i)
s := zbar.NewScanner()
s.SetConfig(0, zbar.CFG_ENABLE, 1)
ret := s.Scan(zimg)
defer s.Destroy()

によりバーコードの読み取りを行っております。

結果ですが、

if ret == 1 {
	zimg.First().Each(func(str string) {
		fmt.Println(str)
	})
}

により、読み取ったバーコードの結果をログとしてprintしているコードになります。

■最後に

go言語でバーコードの読み取りを実現しました。
ラズパイ(ほどのスペックいらないですが)などのプラットフォームに組み込めば即席のバーコードリーダーが作れたりしますね。
出力がログ出力だけなのは微妙なので後で改造しておこう。