カメラで連続読取り
OpenCvSharpとZXingを使用。
前提
カメラがあること。
そして読み取りやすい大きなバーコード・QRコード。
特にバーコードは小さいと読めない。
画質というより接写でのピントが合うカメラがいいだろう。
全体の流れ
1.レイアウト準備
2.パッケージインストール
3.カメラ準備
4.Task処理
5.画像解析
1.レイアウト準備
pictureBox × 1
button × 2
label × 1
2.パッケージインストール
※最新バージョンではない
OpenCvSharp 4.5.5.20211231
OpenCvSharp4.Extensions 4.5.5.20211231
ZXing 0.16.8
OpenCvSharpに依存しない方
3.カメラ準備
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
カメラ映像から一枚一枚画像を取り解析している。
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();
}
おまけ backgroundWorker
古い手だがbackgroundWorkerを使う手段もある。
Invokeの代わりにProgressChangedでUI処理をする。
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);
}