【QRコード読取】WebカメラでQRコード読取CSV出力アプリ_OpenCV_ZXing使用

C#.NET

ad2

【QRコード読取】WebカメラでQRコード読取CSV出力アプリ_OpenCV_ZXing使用

QRコード読取&CSV出力のアプリ開発

今回は、QRコードをWebカメラで読取⇒読み取ったデータをCSV出力するアプリ(C#.Net開発)を作ってみました。

非同期で繰り返し何度でもQRコードを読み取れる仕様です。

簡単にデータフロー図を書きました。

flow

QRコードをWebカメラで読み取り、CSVファイル出力する流れになります。

画像処理ライブラリOpenCVSharpを使ってみた

 スポンサードリンク

OpenCVとは、画像処理・画像解析および機械学習等の機能を持つC/C++、Java、Python、MATLAB用ライブラリです。

今回は、VisualStudioで開発したので、NugetからOpenCVをダウンロードしました。

openCV_get

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

OpenCVsharp_download

検索欄に「OpenCVSharp」と入力して検索します。今回は、「OpenCvSharp4」という、赤枠で囲ったライブラリをインストールしました。

スポンサードリンク

QRコード読取にライブラリZXingを使ってみた

ZXingとは、オープンソースの1D/2Dバーコード読み取りライブラリ。(こちらに画像アップデートで二次元コード読取できるサイトがあります。)

ZXingもOpenCVSharpと同様にNugetパッケージからインストールできます。

今回は、C#.Net開発なので、ZXing.Netライブラリをインストールします。

ZXing_get

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ですね。その他は、おまけみたいなものですので、実際に試す方がいれば、その辺は工夫して下さい。

designer

これにコンポーネントの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コードを読み取った際の画面の表示は次のようになります。

result

CSV出力結果

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

csv_result

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

csv_data

スポンサードリンク

 

振り返って

今回、画像処理や、二次元コード処理などの知識が全くない状態からググって調べながら自分なりにアプリを開発しました。

OpenCVやZXingのライブラリを利用して、ここまでのアプリが出来て、自分なりに満足しています。

最近では、QRコード決済など、二次元コードや画像処理技術が活用される場面が多くなってきていますね。

この記事を見て参考になった方がいれば、幸いです。