今回はAForge.NETとdelegateを使うやり方。
delegateの練習にも。使わない方法も追記。
前の記事はOpenCvSharpの古いバージョンに依存中。
(CaptureMat➡Bitmap(pictureBox.Imageと解析用)に変換するのがTask内で簡単にできる)
参考にさせていただきました。
事前準備
以下を追加
AForge.Video
AForge.Video.DirectShow
ZXing.Net
pictureBox x1
button x2
label1 x1
カメラ・画像解析の準備
Form1.cs
using System;
using System.Drawing;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
using AForge.Video;
using AForge.Video.DirectShow;
using ZXing;
FilterInfoCollection videoDevices;
VideoCaptureDevice videoSource;
ZXing.BarcodeReader reader = new ZXing.BarcodeReader();
bool code_request = true;
Bitmap bmp;
delegate void DelegateProcess();
Task task;
private void Form1_Load(object sender, EventArgs e)
{
reader.Options = new ZXing.Common.DecodingOptions
{
TryHarder = true,
//読み取るコードの種類
PossibleFormats = new[] { BarcodeFormat.QR_CODE, BarcodeFormat.EAN_13 }.ToList()
};
videoDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice);
if (videoDevices.Count == 0)
{
MessageBox.Show("カメラがありません");
return;
}
//外部カメラ優先
videoSource = new VideoCaptureDevice(videoDevices[videoDevices.Count-1].MonikerString);
videoSource.NewFrame += new NewFrameEventHandler(video_NewFrame);
videoSource.Start();
}
//pictureBoxに反映
private void video_NewFrame(object sender, NewFrameEventArgs eventArgs)
{
pictureBox1.Image = (Bitmap)eventArgs.Frame.Clone();
}
Taskとdelegate
非同期⇔UIときたらdelegateかInvoke。
Form1.cs
private void Form1_Shown(object sender, EventArgs e)
{
//pictureBoxサイズをユーザ側で変更できないならここで一回呼び出す
bmp= new Bitmap(pictureBox1.Width, pictureBox1.Height);
codeRead();
}
private void codeRead()
{
DelegateProcess process = new DelegateProcess(bitMapInput);
Result result;
try
{
task = Task.Run(() =>
{
while (code_request)
{
//そこまでまめにやらなくていい
System.Threading.Thread.Sleep(1000);
//UI情報取得(pictureBox.ImageをBitmapに変換)
this.Invoke(process);
result = reader.Decode(bmp);
if (result != null)
{
Console.WriteLine(result.Text);
//label(UI)に反映
Invoke(new Action(() =>
{
label1.Text = result.Text;
}));
}
}
});
}
catch (Exception e) { Console.WriteLine(e.Message);}
}
private void bitMapInput()//UIを取得する処理
{
try
{
if (pictureBox1.Image != null)
using (Graphics g = Graphics.FromImage(bmp))
{
g.DrawImage(pictureBox1.Image, 0, 0);
}
}
catch(InvalidOperationException e) { Console.WriteLine(e.Message); }
}
仕上げ
Form1.cs
private async void stopCamera()
{
if (videoSource != null && videoSource.IsRunning)
{
code_request = false;
videoSource.SignalToStop();
videoSource.WaitForStop();
await task;
}
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
stopCamera();
}
private void stop_button_Click(object sender, EventArgs e)
{
stopCamera();
}
private void start_button_Click(object sender, EventArgs e)
{
code_request = true;
videoSource.Start();
codeRead();
}
おまけ delegateを使わないCopyFromScreen
メイン画面をCaptureしUIへ干渉しなければいい。
ただし画像は大きい。位置情報とサイズの考慮でどうにかなる?
➡なりました(追記)
QRコードは問題ないがバーコードだと解像度を上げるかdelegateを使った方が良い。
//全体キャプチャ
//Rectangle bounds = Screen.PrimaryScreen.Bounds;
Rectangle bounds = pictureBox1.RectangleToScreen(pictureBox1.ClientRectangle);
Bitmap bmp = new Bitmap(Bounds.Width, bounds.Height);
Point upperLeftSource = bounds.Location;
Result result;
try
{
task = Task.Run(() =>
{
while (code_request)
{
System.Threading.Thread.Sleep(1000);
using (Bitmap bitmap = new Bitmap(bounds.Width, bounds.Height))
{
// Graphicsオブジェクトを使用して画面全体をキャプチャ
//using (Graphics g = Graphics.FromImage(bitmap))
//{
//g.CopyFromScreen(System.Drawing.Point.Empty, System.Drawing.Point.Empty, bounds.Size);
//}
using (Graphics g = Graphics.FromImage(bmp))
{
g.CopyFromScreen(
upperLeftSource, System.Drawing.Point.Empty,
bounds.Size, CopyPixelOperation.SourceCopy);
}
Result result = reader.Decode(bitmap);
if (result != null)
{
Invoke(new Action(() =>
{
label1.Text = result.Text;
}));
}
}
}
});
}
参考