Có gì mới?
Diễn đàn ứng dụng xử lý ảnh công nghiệp trong sản xuất

Đây là một tin nhắn khách mời. Đăng ký một tài khoản miễn phí ngay hôm nay để trở thành một thành viên! Sau khi đăng nhập, bạn sẽ có thể tham gia trang web này bằng cách thêm các chủ đề và bài đăng của riêng bạn, cũng như kết nối với các thành viên khác thông qua hộp thư đến riêng của bạn!

C# Phát hiện chuyển động trong vùng quan tâm (ROI) phức tạp (nhiều ROI)

Ngôn ngữ C#

hieule

Thành viên BQT
CTO
Admin
Dev Leader
Machine Vision Expert
Green Industry
Tham gia
21/10/2023
Bài viết
24
Điểm
1,039
Nơi ở
Việt Nam
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
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;


2023-11-10-06h01-16.png

+ Để 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;
Trong đó hàm Tick của Timer được khai như sau:
C#:
private void timer1_Tick(object sender, EventArgs e)
{
    //Todo
}
+ Để thu ảnh từ camera, sử dụng đối tượng VideoCapture của OpenCvSharp và được khai báo như sau:
C#:
 VideoCapture cap = new VideoCapture(0);
+ 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:
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);

                    }
                }
    
            }

        }
+ Để 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:
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();
 }
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
 

Đính kèm

  • 20231110_083941.mp4
    4.8 MB · Lượt xem: 4
Sửa lần cuối:

Thai_TTTM

Thành viên
Tham gia
12/10/2024
Bài viết
1
Điểm
3
Tuổi
31
Nơi ở
Bắc Ninh
Admin có thể mở giúp chức năng hạn chế người xem nội dung bài viết được không ạ ?
Mh người mới tham gia diễn đàn để học hỏi, nhưng chưa đủ tương tác để xem được đầy đủ bài viết này.
Xin cảm ơn.
 
Bình luận

admin

The inspirator
Thành viên BQT
Co-Founder
Admin
Machine Vision Expert
Green Industry
Tham gia
10/06/2021
Bài viết
55
Điểm
9,104
Nơi ở
Việt Nam
Admin có thể mở giúp chức năng hạn chế người xem nội dung bài viết được không ạ ?
Mh người mới tham gia diễn đàn để học hỏi, nhưng chưa đủ tương tác để xem được đầy đủ bài viết này.
Xin cảm ơn.
bạn cần có 50 likes để nhìn thấy bài hoặc link để tải dữ liệu. Hãy viết bài và đóng góp cho diễn đàn để đạt được một tiêu nhé
 
  • Like
Các phản ứng: sơn
Bình luận
Top