Bài viết này sẽ giới thiệu với các bạn:
+ Cách đọc ảnh từ camera và hiển thị lên Winforms
+ Cách vẽ vùng quan tâm trên giao diện Winforms bằng con trỏ
+ Cách tạo vùng quan tâm (ROI - region of interest) phức tạp từ nhiều ROI.
+ Cách phát hiện chuyển động từ vùng quan tâm đã tạo.
(Dự án này sử dụng Visual Studio C# kết hợp với OpenCvSharp)
+ Mở Visual Studio và tạo dự án với lựa chọn là Winforms với .Net Framework 4.8
+ Thực hiện cài đặt OpenCvSharp bằng cách thêm OpenCvSharp từ NuGet Package Manager
+ Thiết kế các điều khiển như trong hình dưới:
(1) và (2) là các điều khiển PictureBox lần lượt là pictureBox1 và pictureBox2 trong đó pictureBox1 hiển thị cac ROI được vẽ lên ảnh thu được và pictureBox2 hiển thị xử lý và ghép các ROI thành một ROI chung
(3) và (4) là các điều khiển TrackBar lần lượt là trackBar1 và trackBar2
(5) là nút lệnh tạo ROI kiểu Button tên là button1
(6) là nút lệnh xóa hết các ROI kiểu Button tên là button2
(7) là nhãn hiển thị thông tin hướng dẫn sử dụng kiểu Label tên là Label1
(8) là nhãn hiển thị trạng thái có chuyển động trong ảnh kiểu Label tên là Label2
+ Để thu ảnh từ camera liên tục, ta sử dụng Timer và sự kiện Tick của nó để lấy ảnh từ camera, khai báo Timer như sau:
Trong đó hàm Tick của Timer được khai như sau:
+ Để thu ảnh từ camera, sử dụng đối tượng VideoCapture của OpenCvSharp và được khai báo như sau:
+ Ngoài ra còn có m ột số biến được tạo với các ý nghĩa từng cái như trong chú thích:
+ Để vẽ ROI lên pictureBox1, thực hiện tạo các sự kiện cho pictureBox1 như sau:
+ Để thu ảnh từ camera và gộp các ROI đơn lẻ vào thành một ROI chung thì thực hiện trong ham Tick của Timer như sau:
+ Các sự kiện tạo ROI (button1) và xóa các ROI (button2) được thực hiện như sau:
Link để tải tệp chương trình về (mật khẩu: nhatquangmvt):
Kết quả như trong tệp MP4 đính kèm
+ Cách đọc ảnh từ camera và hiển thị lên Winforms
+ Cách vẽ vùng quan tâm trên giao diện Winforms bằng con trỏ
+ Cách tạo vùng quan tâm (ROI - region of interest) phức tạp từ nhiều ROI.
+ Cách phát hiện chuyển động từ vùng quan tâm đã tạo.
(Dự án này sử dụng Visual Studio C# kết hợp với OpenCvSharp)
+ Mở Visual Studio và tạo dự án với lựa chọn là Winforms với .Net Framework 4.8
+ Thực hiện cài đặt OpenCvSharp bằng cách thêm OpenCvSharp từ NuGet Package Manager
+ Thiết kế các điều khiển như trong hình dưới:
(1) và (2) là các điều khiển PictureBox lần lượt là pictureBox1 và pictureBox2 trong đó pictureBox1 hiển thị cac ROI được vẽ lên ảnh thu được và pictureBox2 hiển thị xử lý và ghép các ROI thành một ROI chung
(3) và (4) là các điều khiển TrackBar lần lượt là trackBar1 và trackBar2
(5) là nút lệnh tạo ROI kiểu Button tên là button1
(6) là nút lệnh xóa hết các ROI kiểu Button tên là button2
(7) là nhãn hiển thị thông tin hướng dẫn sử dụng kiểu Label tên là Label1
(8) là nhãn hiển thị trạng thái có chuyển động trong ảnh kiểu Label tên là Label2
C#:
private System.Windows.Forms.PictureBox pictureBox1;
private System.Windows.Forms.PictureBox pictureBox2;
private System.Windows.Forms.TrackBar trackBar1;
private System.Windows.Forms.TrackBar trackBar2;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.Button button1;
private System.Windows.Forms.Button button2;

+ Để thu ảnh từ camera liên tục, ta sử dụng Timer và sự kiện Tick của nó để lấy ảnh từ camera, khai báo Timer như sau:
C#:
private System.Windows.Forms.Timer timer1;
C#:
private void timer1_Tick(object sender, EventArgs e)
{
//Todo
}
C#:
VideoCapture cap = new VideoCapture(0);
C#:
//Biến chứa các điểm của ROI trên điều khiển PictureBox, Point là đối tượng trong lớp System.Drawing;
List<List<Point>> mRoiOnPicCtrl = new List<List<Point>>();
//Biến chứa các điểm của ROI trên ảnh thu được từ camera
List<List<Point>> mRoiOnImage = new List<List<Point>>();
//Biến chứa các điểm của ROI trên ảnh OpenCvSharp, Point là đối tượng trong OpenCvSharp
List<List<OpenCvSharp.Point>> POINTS = new List<List<OpenCvSharp.Point>>();
//Biến cho phép hiển thị ROI
bool enableDraw = false;
//Biến trạng thái thể hiện có lệnh vẽ ROI mới
bool CreateRoiCmd = false;
//Biến chứa các ảnh thu được
List<Mat> frames = new List<Mat>();
//Sử dụng BackgroundSubtractorMOG để phát hiện chuyển động trong ảnh
BackgroundSubtractorMOG mog = BackgroundSubtractorMOG.Create(100);
+ Để vẽ ROI lên pictureBox1, thực hiện tạo các sự kiện cho pictureBox1 như sau:
C#:
private void pictureBox1_MouseClick(object sender, MouseEventArgs e)
{
switch(e.Button)
{
case MouseButtons.Left:
if (enableDraw == true)
mRoiOnPicCtrl.Last().Add(new Point(e.X, e.Y));
break;
case MouseButtons.Right:
enableDraw = true;
break;
}
pictureBox1.Invalidate();
}
C#:
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
if (mRoiOnPicCtrl.Count < 1)
return;
if(enableDraw==true)
{
if (mRoiOnPicCtrl.Last().Count >= 1)
{
Pen pn = new Pen(Color.Red, 1f);
Point pf = mRoiOnPicCtrl.Last().First();
Rectangle rFirst = new Rectangle(pf.X - 4, pf.Y - 4, 8, 8);
e.Graphics.DrawRectangle(pn, rFirst);
if (mRoiOnPicCtrl.Last().Count > 1)
{
Point pl = mRoiOnPicCtrl.Last().Last();
Rectangle rEnd = new Rectangle(pl.X - 4, pl.Y - 4, 8, 8);
e.Graphics.DrawRectangle(pn, rEnd);
}
if (mRoiOnPicCtrl.Last().Count >= 2)
{
Pen p = new Pen(Color.Green, 2f);
for (int i = 0; i < mRoiOnPicCtrl.Last().Count - 1; i++)
{
Point p1 = mRoiOnPicCtrl.Last()[i];
Point p2 = mRoiOnPicCtrl.Last()[i + 1];
e.Graphics.DrawLine(p, p1, p2);
}
}
if (mRoiOnPicCtrl.Last().Count > 1 && Distance(mRoiOnPicCtrl.Last().First(), mRoiOnPicCtrl.Last().Last()) < 6)
{
//Thêm ROI mới trên hệ tọa độ Hình ảnh
mRoiOnImage.Add(new List<Point>());
for (int j = 0; j < mRoiOnPicCtrl.Last().Count; j++)
{
//Chuyển đổi điểm từ hình ảnh sang tọa độ hình ảnh
mRoiOnImage.Last().Add(Point.Round(GetP(sI.Width, sI.Height, pictureBox1.Width, pictureBox1.Height, mRoiOnPicCtrl.Last()[j].X, mRoiOnPicCtrl.Last()[j].Y)));
}
foreach (var RoI in mRoiOnImage)
{
POINTS.Add(new List<OpenCvSharp.Point>());
List<Point> Points = RoI;
for (int k = 0; k < Points.Count; k++)
{
POINTS.Last().Add(new OpenCvSharp.Point(Points[k].X, Points[k].Y));
}
}
mRoiOnPicCtrl.Last()[mRoiOnPicCtrl.Last().Count - 1] = mRoiOnPicCtrl.Last()[0];
button1.Enabled = true;
button2.Enabled = true;
enableDraw = false;
}
}
//Vẽ các ROI cũ
if (mRoiOnPicCtrl.ToList().Count > 1)
{
for (int k = 0; k < mRoiOnPicCtrl.ToList().Count - 1; k++)
{
List<Point> points = mRoiOnPicCtrl[k];
if (points.Count < 2)
continue;
Pen p = new Pen(Color.Green, 2f);
for (int j = 0; j < points.Count - 1; j++)
{
Point p1 = points[j];
Point p2 = points[j + 1];
e.Graphics.DrawLine(p, p1, p2);
}
}
}
}
if(enableDraw==false)
{
foreach (var _points in mRoiOnPicCtrl)
{
List<Point> points = _points;
if (points.Count < 2)
continue;
Pen p = new Pen(Color.Green, 2f);
for (int j = 0; j < points.Count - 1; j++)
{
Point p1 = points[j];
Point p2 = points[j + 1];
e.Graphics.DrawLine(p, p1, p2);
}
}
}
}
+ Các sự kiện tạo ROI (button1) và xóa các ROI (button2) được thực hiện như sau:
C#:
private void button1_Click(object sender, EventArgs e)
{
button1.Enabled = false;
button2.Enabled = false;
enableDraw = true;
mRoiOnPicCtrl.Add(new List<Point>());
pictureBox1.Invalidate();
pictureBox2.Invalidate();
}
C#:
private void button2_Click(object sender, EventArgs e)
{
mRoiOnImage.Clear();
mRoiOnPicCtrl.Clear();
pictureBox1.Invalidate();
pictureBox2.Invalidate();
}
Kết quả như trong tệp MP4 đính kèm
Đính kèm
Sửa lần cuối: