【QRコード読取】WebカメラでQRコード読取CSV出力アプリ_OpenCV_ZXing使用
QRコード読取&CSV出力のアプリ開発
今回は、QRコードをWebカメラで読取⇒読み取ったデータをCSV出力するアプリ(C#.Net開発)を作ってみました。
非同期で繰り返し何度でもQRコードを読み取れる仕様です。
簡単にデータフロー図を書きました。

QRコードをWebカメラで読み取り、CSVファイル出力する流れになります。
画像処理ライブラリOpenCVSharpを使ってみた
スポンサードリンク


OpenCVとは、画像処理・画像解析および機械学習等の機能を持つC/C++、Java、Python、MATLAB用ライブラリです。
今回は、VisualStudioで開発したので、NugetからOpenCVをダウンロードしました。

プロジェクト>>NuGetパッケージの管理をクリック。

検索欄に「OpenCVSharp」と入力して検索します。今回は、「OpenCvSharp4」という、赤枠で囲ったライブラリをインストールしました。
QRコード読取にライブラリZXingを使ってみた
ZXingとは、オープンソースの1D/2Dバーコード読み取りライブラリ。(こちらに画像アップデートで二次元コード読取できるサイトがあります。)
ZXingもOpenCVSharpと同様にNugetパッケージからインストールできます。
今回は、C#.Net開発なので、ZXing.Netライブラリをインストールします。

WindowsFormでの画面デザイン
画面のデザインの説明をしていきます。
分かりやすい様にキャプチャ画面にコントロール部品の配置を書いてみました。
GroupBox(pictureGroupBox)の中にPictureBox(qr_pictureBox)を設置し、その中にPictureBox(show_pictureBox)を設置しています。
PictureBox(qr_pictureBox)は、Webカメラの映像を映す為のもので、PictureBox(show_pictureBox)は、QRコードを読み取った際にOKマークを
表示する為のPictureBoxなので、無くても問題ないです。
その他に、RichTextBoxBox(barcodeFormatBox)は、二次元コードのフォーマット名を表示させるデバッグ用途で設置しました。
RichTextBoxBox(readResultBox)は、QRコードのデータ中身を表示させる用です。
TextBoxBox(resultOKtextBox)は、読取OKの文字列を表示用で設置しました。
肝心なのは、pictureBoxですね。その他は、おまけみたいなものですので、実際に試す方がいれば、その辺は工夫して下さい。

これにコンポーネントのbackgroundWorker1とbackgroundWorker2を追加しています。
ソースコード全容
では、ソースコードを載せていきます。一気に全ソース載せましたので、ご自由にコピペして実際に動作させてみて下さい。
綺麗で、見やすいコードを書けるほどのスキルはもっていませんので、冗長なコードかもしれません。ご了承下さい。
backgroundWorkerを活用して、OpenCVのVideoCaptureとMatを使用してWebカメラの映像を繰り返しキャプチャして読み込ませて、
QRコードがキャプチャされたら、ZXingのBarcodeReaderでデコード処理してQRコードを読み取ります。
読み取ったデータを画面表示させ、CSV出力を内部処理する。
この流れをアプリが起動している間、ずっと繰り返すようなソースコードになっています。
using OpenCvSharp; using OpenCvSharp.Extensions; using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.IO; using System.Linq; using System.Threading.Tasks; using System.Windows.Forms; using ZXing; namespace QR_reader { public partial class Form1 : Form { bool qrresult = true; public Form1() { InitializeComponent(); } /// <summary> /// 画面起動時 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void Form1_Load(object sender, EventArgs e) { //親画像ボックスに子画像ボックスを設定する show_pictureBox.Parent = qr_pictureBox; //バックグランド処理1の実行開始 this.backgroundWorker1.RunWorkerAsync(); } /// <summary> /// バックグラウンド処理 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void BackgroundWorker1_DoWork(object sender, DoWorkEventArgs e) { using (VideoCapture capture = new VideoCapture(0)) { using (Mat normalframe = new Mat()) //無限ループ while (qrresult == true) { //キャプチャ読込 capture.Read(normalframe); show_pictureBox.Image = null; if (!normalframe.Empty()) { //画像表示 this.qr_pictureBox.Image = normalframe.ToBitmap(); //画像処理QRコード //コードの解析 ZXing.BarcodeReader reader = new ZXing.BarcodeReader(); reader.Options = new ZXing.Common.DecodingOptions { TryHarder = true, PossibleFormats = new[] { BarcodeFormat.QR_CODE }.ToList() }; //QRコードのデコーダ処理 Result result = reader.Decode(normalframe.ToBitmap()); if (result != null) { //バックグラウンド処理1 プログレス更新時 // ReportProgressメソッドを使って、ProgressChangedイベントを発生させる this.backgroundWorker1.ReportProgress(0, result); //2秒間待機させる⇒処理が早すぎる為?エラーになるので、待ち時間を設けた。 System.Threading.Thread.Sleep(2000); //バックグラウンド処理2実行 this.backgroundWorker2.RunWorkerAsync(); } } } } } /// <summary> /// プログレス更新時処理 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void BackgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e) { //QR読取結果の引数を取得 Result result = (Result)e.UserState; //結果をTextBoxコントロールに表示 barcodeFormatBox.Text = result.BarcodeFormat.ToString(); readResultBox.Text = result.Text; //OK画像の読込 FileStream hStream = new FileStream(@"./imgok.jpg", FileMode.Open); //OKマークを表示させる show_pictureBox.Image = Image.FromStream(hStream); hStream.Close(); resultOKtextBox.Text = "読取OK"; resultOKtextBox.BackColor = Color.LimeGreen; qrresult = false; } /// <summary> /// CSVファイル出力処理 /// </summary> private void CsvOutput() { //QRコードデータ string strQrData = readResultBox.Text.ToString(); string[] tempArrayData; List<string> stArrayData = new List<string>(); tempArrayData = strQrData.Split(','); //カンマ区切りで配列に格納 for (int iCount = 0; iCount < tempArrayData.Length; iCount++) { stArrayData.Add(tempArrayData[iCount]); //リストに追加 } string timeStrA = DateTime.Now.ToString("yyyyMMddHHmmss"); StreamWriter swA = new StreamWriter(@"H:\ブログ\ブログネタ\C#\QRcode\" + timeStrA + ".csv", false, System.Text.Encoding.GetEncoding("shift_jis")); string str2A = string.Join(",", stArrayData); //csv書込み内容 swA.WriteLine(str2A.ToString()); swA.Close(); } /// <summary> /// バックグラウンド処理の完了処理 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void BackgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { //5秒間待機させる⇒連続でQRコードを読み取らせない為に必要。 System.Threading.Thread.Sleep(5000); //テキストボックスの中身をクリア resultOKtextBox.Text = string.Empty; barcodeFormatBox.Text = string.Empty; readResultBox.Text = string.Empty; resultOKtextBox.BackColor = Color.White; qrresult = true; this.backgroundWorker1.RunWorkerAsync(); } /// <summary> /// バックグラウンド処理2 QRコード読込 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void BackgroundWorker2_DoWork(object sender, DoWorkEventArgs e) { Task.Run(() => Invoke(new Action(CsvOutput))); } /// <summary> /// 閉じるボタン押下処理 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void button1_Click(object sender, EventArgs e) { ActiveForm.Close(); } } }
動作結果画面
テストとして、文字列が「QRコード,TEST,読取,Extra-Lab,2019,05,15」というデータが入ったQRコードを用意して読み取ります。
実際にQRコードを読み取った際の画面の表示は次のようになります。

CSV出力結果
QRコードのデータ内容をカンマ区切りでlist化してcsvファイルを作成する仕様にしてる。

CSVを開くと、下図のようにQRコードから読み取ったデータが入っています。

振り返って
今回、画像処理や、二次元コード処理などの知識が全くない状態からググって調べながら自分なりにアプリを開発しました。
OpenCVやZXingのライブラリを利用して、ここまでのアプリが出来て、自分なりに満足しています。
最近では、QRコード決済など、二次元コードや画像処理技術が活用される場面が多くなってきていますね。
この記事を見て参考になった方がいれば、幸いです。