GoCVでQRコードを読み取る
はじめに
やっと…長いビルドが終わり…やっとだぜ…やっと動かして遊べる… OpenCV4.5.3をGoCVから呼び出して動かしてみましょう。
まずはgocvでQRCodeを読み出して文字列を取得するまでをやります。
インストールやらはこちらの記事を参考にしてください。 Raspberry piで環境作ってやってますけど、WindowsやMacでもコードは共通なはずです。
Raspberry piにGoとgocv(OpenCV 4)環境をインストールする
Raspberry pi にOpenCV 4.5.3のビルドで100%になったけど進まなくなったときの対処
Hello,GoCV
公式サイトに書かれているコードを書き出します。
package main
import (
"gocv.io/x/gocv"
)
func main() {
webcam, _ := gocv.OpenVideoCapture(0)
window := gocv.NewWindow("Hello")
img := gocv.NewMat()
for {
webcam.Read(&img)
window.IMShow(img)
window.WaitKey(1)
}
}
SSHで接続していたのですが、ERRORがでます。 これはGUIが無いのにカメラの映像を出そうとしてるからですね。 実行してみましょう。
go run readQRCode.go
[ WARN:0] global /tmp/opencv/opencv-4.5.3/modules/videoio/src/cap_gstreamer.cpp (1081) open OpenCV | GStreamer warning: Cannot query video position: status=1, value=1, duration=-1
Unable to init server: Could not connect: Connection refused
terminate called after throwing an instance of 'cv::Exception'
what(): OpenCV(4.5.3) /tmp/opencv/opencv-4.5.3/modules/highgui/src/window_gtk.cpp:635: error: (-2:Unspecified error) Can't initialize GTK backend in function 'cvInitSystem'
SIGABRT: abort
PC=0x7496ef14 m=0 sigcode=4294967290
signal arrived during cgo execution
goroutine 1 [syscall, locked to thread]:
runtime.cgocall(0xd3df0, 0x1047f58)
/usr/local/go/src/runtime/cgocall.go:156 +0x5c fp=0x1047f40 sp=0x1047f28 pc=0x3fba0
gocv.io/x/gocv._Cfunc_Window_New(0xff4b88, 0x0)
_cgo_gotypes.go:7582 +0x2c fp=0x1047f54 sp=0x1047f40 pc=0xc9044
gocv.io/x/gocv.NewWindow({0x1168e3, 0x5})
/home/pi/work/pkg/mod/gocv.io/x/gocv@v0.28.0/highgui.go:39 +0x74 fp=0x1047f70 sp=0x1047f54 pc=0xc9320
main.main()
/home/pi/src/QRCode/readQRCode.go:12 +0x50 fp=0x1047fbc sp=0x1047f70 pc=0xc9e40
runtime.main()
/usr/local/go/src/runtime/proc.go:255 +0x278 fp=0x1047fe4 sp=0x1047fbc pc=0x732f8
runtime.goexit()
/usr/local/go/src/runtime/asm_arm.s:838 +0x4 fp=0x1047fe4 sp=0x1047fe4 pc=0x9dfd4
trap 0x0
error 0x0
oldmask 0x0
r0 0x0
r1 0x7ed57654
r2 0x0
r3 0x8
r4 0x76fc3968
r5 0x6
r6 0x7ed57654
r7 0xaf
r8 0xd9419c
r9 0xd941b8
r10 0xd941d0
fp 0xff67a8
ip 0x0
sp 0x7ed57650
lr 0xffffffff
pc 0x7496ef14
cpsr 0x10
fault 0x0
exit status 2
リモートデスクトップでつなぎ直して実行すると映像が取得できるはずです。 GUIがあるとこんな風に表示されます。
これで動いていることは確認出来ました。 からかい上手の高木さん 12巻がでましたね。 癒やされる。
QRCodeを生成するコードを作ります
QRCodeの生成するコードを書きましょう。 Goでパッケージ作ってくれている人がいるのでくっそ簡単です。
go get github.com/boombuler/barcode
package main
import (
"image/png"
"os"
"github.com/boombuler/barcode"
"github.com/boombuler/barcode/qr"
)
func main() {
// Create the barcode
qrCode, _ := qr.Encode("ちんこちんこちーんこビーム", qr.M, qr.Auto)
// Scale the barcode to 200x200 pixels
qrCode, _ = barcode.Scale(qrCode, 200, 200)
// create the output file
file, _ := os.Create("qrcode.webp")
defer file.Close()
// encode the barcode as png
png.Encode(file, qrCode)
}
生成されたのがこれです。
どうかしてるとしか思えないですがまぁいいでしょう。
QRCodeを読み取るコードを作成
gocvのサンプルみたいなものはネット上に転がっていないので、PythonやC++で書かれたOpenCVのコードを参考に組み立てていきます。
points := gocv.NewMat()
straight_qrcode := gocv.NewMat()
実行結果を取得するMat型を作るときはこうやって書きます。
var points gocv.Mat
こんな風に書くと、C言語で書かれたOpenCVを呼び出すときにNull参照になって落ちます。
カメラ画像をinputに検出して、QRコードの文字列にDecodeしています。
qr.Detect(img, &points)
strtmp = qr.Decode(img, points, &straight_qrcode)
やっていることはこれだけです。
コード全体はこうなりました。
package main
import (
"fmt"
"gocv.io/x/gocv"
)
func main() {
webcam, _ := gocv.OpenVideoCapture(0)
window := gocv.NewWindow("Hello")
img := gocv.NewMat()
qr := gocv.NewQRCodeDetector()
fmt.Println("QRCode Read")
points := gocv.NewMat()
straight_qrcode := gocv.NewMat()
var strtmp string
for {
webcam.Read(&img)
window.IMShow(img)
qr.Detect(img, &points)
strtmp = qr.Decode(img, points, &straight_qrcode)
// strtmp := qr.DetectAndDecode(img, &points, &straight_qrcode)
if len(strtmp) > 0 {
fmt.Println(strtmp)
}
}
}
実行結果
QRコードをかざしたら文字列が取得できると思います。
まとめ
QRCodeの読み取りと結果の習得は、秒速でしたわ。ガハハ。 Raspberry piで動かしてもそこそこ動くし、Pythonで書いたようなソフトよりも体感早い気がします。 良いんじゃないでしょうか。 今日はこんなところですかね。