OpenCVSharp 카메라 제어 #1 ( 카메라 영상 출력 )

Software/C#|2023. 3. 5. 12:41
반응형

장비제어 프로그램에서 빠질수 없는 부분이 카메라 제어 입니다. 기존에 C++ Builder를 이용하여 장비제어를 했을때도 OpenCV를 사용했지만 OpenCV 버젼이 올라가고 클래스 기반으로 라이브러리가 변경되면서 C++ Builder의 구조적인 문제로 인해 더이상 상위 버젼의 OpenCV 릃 사용할 수가 없었고, C#으로 개발툴을 변경하면서 OpenCVSharp을 적용해 보았습니다. 이번장에서는 기본적으로 카메라 영상을 화면에 출력하는 방법에 대해 구현합니다. 

 

카메라 영상 제어를 위한 클래스를 구현했고 Thread 로 영상을 화면에 출력하도록 했습니다.

 

1. Winform 프로젝트를 하나 만듭니다. 

2. nuget 에서 openCVSharp 관련 컨트롤을 등록시켜 줍니다.

OpenCVSharp 사용을 위한 컨트롤 등록
OpenCVSharp 사용을 위한 컨트롤 등록

3. MainForm 에 pictureBox 1개(640 x 480)와 Button 2개(start, stop) 을 올려 줍니다.

   *  pictureBox의 크기는 카메라의 해상도에 맞추어 조정하시면 됩니다. 

 

4. 아래는 구현된 카메라 클래스 입니다. 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using OpenCvSharp;
using OpenCvSharp.Extensions;

namespace CameraControl
{
    public class CameraThread
    {
        private delegate void SafeCallDelegate(Bitmap frame);

        readonly private VideoCapture capture = new VideoCapture();
        readonly private Mat sourceFrame = new();
        private OpenCvSharp.Point displaySize;

        public int cameraNumber { get; set; } = 0;
        public bool isCameraRunning { get; set; } = false;

        public PictureBox display;
        public PictureBox Display
        {
            set
            {
                this.display = value;
                this.displaySize.X = display.Width;
                this.displaySize.Y = display.Height;
            }
        }
        //-------------------------------------------------------------------------------------
        public CameraThread(PictureBox pictureBox, int cameraNumber)
        {
            this.display = pictureBox;

            displaySize.X = pictureBox.Width;
            displaySize.Y = pictureBox.Height;

            capture.FrameWidth = displaySize.X;
            capture.FrameHeight = displaySize.Y;

            this.cameraNumber = cameraNumber;
        }
        //-------------------------------------------------------------------------------------
        public Int32 Initialize()
        {
            Int32 result = 1;
            capture.Open(cameraNumber);

            if (capture.IsOpened()) result = 0;

            return result;
        }
        //-------------------------------------------------------------------------------------
        public void Run()
        {
            capture.Open(cameraNumber);    // 연결된 카메라를 Open 합니다. 

            using (Mat displayFrame = new())  // 영상 출력을 위한 Mat 생성 
            {
                while (isCameraRunning)
                {
                    capture.Read(sourceFrame);  // 카메라에서 영상 Source Frame 으로 읽어옵니다.

                    if (!sourceFrame.Empty())
                    {
                        Cv2.CopyTo(sourceFrame, displayFrame);   // source frame의 영상을 출력 영상 frame 롤 복사합니다. 
                        UpdateFrame(BitmapConverter.ToBitmap(displayFrame));  // 출력영상을 화면에 보여 줍니다.
                    }
                }
            }

            capture.Release();
            GC.Collect();
        }
        //-------------------------------------------------------------------------------------
        private void UpdateFrame(Bitmap frame)
        {
            if (display != null)
            {
                if (display.InvokeRequired)
                {
                    var d = new SafeCallDelegate(UpdateFrame);
                    display.Invoke(d, new object[] { frame });
                }
                else
                {
                    display.Image = frame;
                }
            }
        }
        //-------------------------------------------------------------------------------------
   }
}

 

 * 영상제어 클래스에서 source frame 와 display frame 을 분리한 이유는 source frame 에서 영상에 대한 제어를 활용하고 그 결과를 display frame를 통해 출력하기 위해 별도로 분리했습니다. 

 

5. 위에 구현된 클래스를 이용하여 메인 화면에 영상을 출력합니다.

using OpenCvSharp;
using System;
using System.Windows.Forms;

namespace CameraControl
{
    public partial class Form1 : Form
    {
        private Thread thread;
        readonly private CameraThread cameraThread;

        public Form1()
        {
            InitializeComponent();

            cameraThread = new CameraThread(pictureBox1, 0);  // 0번 카메라 출력 
            cameraThread.Initialize();
        }

        private void btnStart_Click(object sender, EventArgs e)
        {
            cameraThread.isCameraRunning = true;

            thread = new Thread(new ThreadStart(cameraThread.Run));
            thread.Start();
        }

        private void btnStop_Click(object sender, EventArgs e)
        {
            if (thread.IsAlive)
            {
                cameraThread.isCameraRunning = false;
            }
        }
    }
}

 

반응형

댓글()