【OpenCvSharp+ZXing】C#で簡単カメラ起動➡バーコード・QRコード読取

カメラで連続読取り
OpenCvSharpとZXingを使用。

## 前提
カメラがあること。
そして読み取りやすい大きなバーコード・QRコード。
特にバーコードは小さいと読めない。
画質というより接写でのピントが合うカメラがいいだろう。

## 全体の流れ
1.レイアウト準備
2.パッケージインストール
3.カメラ準備
4.Task処理
5.画像解析
## 1.レイアウト準備
![334e.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3937966/d4cdde9b-e243-18ba-6450-4f93a5db3165.png)

pictureBox　× 1
button      × 2
label       × 1
## 2.パッケージインストール
:::note warn
※最新バージョンではない
OpenCvSharp　4.5.5.20211231
OpenCvSharp4.Extensions 4.5.5.20211231
ZXing　0.16.8
:::
OpenCvSharpに依存しない方

https://qiita.com/A42/items/ec031e411305ffbac5e9

## 3.カメラ準備
```c#:Form1.cs
using OpenCvSharp;
using OpenCvSharp.Extensions;
using ZXing;
using System.Threading;
using System.Threading.Tasks;

VideoCapture capture;
bool code_request = true;
Task task;

    public Form1()
    {
        //i=カメラの最大数で検索
        //0がインカメ, 1以上がアウトカメラや外部接続カメラ
        //今回はインカメより精度が出そうな外部カメラを優先のため減算
        for(int i = 10; i >= 0; i--)
        {
             capture = new VideoCapture(i); 
             if(capture.IsOpened()) break;
        }
        if(!capture.IsOpened())
        {
            MessageBox.Show("camera was not found!");
            this.Close();
        }
        //後述
        cameraStart();
    }
```
## 4.Task
カメラ映像から一枚一枚画像を取り解析している。
```c#
    private void cameraStart()
    {
        //画像処理QRコード
        //コードの解析準備
        ZXing.BarcodeReader reader = new ZXing.BarcodeReader();
        reader.Options = new ZXing.Common.DecodingOptions
        {
            TryHarder = true,
            //コードの種類　※EANは8桁、13桁がある
            PossibleFormats = new[] { BarcodeFormat.QR_CODE, BarcodeFormat.EAN_13 }.ToList()
        };
        task = Task.Run(() =>
        {
            using (Mat normalframe = new Mat())
            while (code_request)
            {
                capture.Read(normalframe);
                if (!normalframe.Empty())
                {
                    this.pictureBox1.Image = normalframe.ToBitmap();
                    //デコーダ処理
                    Result result = reader.Decode(normalframe.ToBitmap());
                    if (result != null)
                    {
                        Console.WriteLine(result.ToString());
                        //処理が早すぎる為待ち時間
                        System.Threading.Thread.Sleep(1000);
                        Invoke(new Action(() =>
                        {
                            label1.Text = result.Text;
                        }));
                    }
                }
            }
        });
    }
    private async void stopCamera()
    {
        if (task.Status == TaskStatus.Running)
        {
            code_request = false;
            await task;
        }
    }
    private void Form1_FormClosing(object sender, FormClosingEventArgs e)
    {
        stopCamera();
    }
    private void start_button_Click(object sender, EventArgs e)
    {
        code_request = true;
        cameraStart();
    }
    private void stop_button_Click(object sender, EventArgs e)
    {
        stopCamera();
    }
```
https://qiita.com/OXamarin/items/eddc9f7f01b691631887

## おまけ backgroundWorker
古い手だがbackgroundWorkerを使う手段もある。
Invokeの代わりにProgressChangedでUI処理をする。
![5555.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3937966/7cf63d5f-42b7-d82b-fbbb-975ac4a34e01.png)

```c#:
    public Form1()
    {
        //カメラ検索中略
        this.backgroundWorker1.WorkerSupportsCancellation = true;
        backgroundWorker1.RunWorkerAsync();
    }
    private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
    {
        ZXing.BarcodeReader reader = new ZXing.BarcodeReader();
        reader.Options = new ZXing.Common.DecodingOptions
        {
            TryHarder = true,
            PossibleFormats = new[] { BarcodeFormat.QR_CODE,BarcodeFormat.EAN_8 }.ToList()
        };
        using(Mat normalframe = new Mat())
        while(code_request)
        {
            capture.Read(normalframe);
            if(!normalframe.Empty())
            {
                this.pictureBox1.Image = normalframe.ToBitmap();    
                Result result = reader.Decode(normalframe.ToBitmap());
                if(result != null)
                {
                    Console.WriteLine(result.ToString());   
                    // ReportProgressメソッドを使って、ProgressChangedイベントを発生させる
                    this.backgroundWorker1.ReportProgress(0, result);
                    System.Threading.Thread.Sleep(1000);
                }
            }
        }
    }
    private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        //結果を取得
        Result result = (Result)e.UserState;
        if(!backgroundWorker1.CancellationPending)
        {
            label1.Text = result.Text;
        }
    }
     private void start_button_Click(object sender, EventArgs e)
     {
         code_request = true;
         backgroundWorker1.RunWorkerAsync();
     }
     private void stop_button_Click(object sender, EventArgs e)
     {
         backgroundWorker1.CancelAsync();
         code_request = false;
     }
     private void Form1_FormClosing(object sender, FormClosingEventArgs e)
    {
        backgroundWorker1.CancelAsync();
        code_request = false;
        while (backgroundWorker1.IsBusy);
    }
```