6.1 개요

  • chunk data를 이용하면 grabResult에서 frame관련 data들을 얻을 수 있다.
  • 예제에서는 frame counter를 textbox에 나타내 본다.

 

6.2 Winform 프로젝트 만들기

  •  Basler 솔루션 안에 BaslerChunkData라는 이름으로 Windows Forms 앱 (.NET Framework) 프로젝트를 만들고 C#작업환경 만들기를 참조하여 Basler.Pylon.dll을 참조 추가한다.

2024.02.08 - [Basler] - 1. c# 작업 환경 만들기

 

1. c# 작업 환경 만들기

Basler 홈페이지에서 제공하는 Pylon Viewer를 설치한다 현재 내가 PC에 설치한 6.2.0 기준으로 (Pylon Viewer 설치 경로)\pylon 6\Development\Assemblies\Basler.Pylon\ 하위에 x64, x86폴더로 나눠져 있고 이중에 자기 os

machinevision-story.tistory.com

 

6.3 UI 디자인

  • 도구 상자에서 Button 3개와 Textbox 1개를 드래그 하여 Form1에 위치 시킨다

  • button과 Name속성과 button의 Text속성을 아래 표와 같이 변경한다.
컨트롤 이름 속성
button1 Name BtnOpen
Text Connect
button2 Name BtnGrab
Text Grab
button3 Name BtnClose
Text Disconnect

 

6.4 코드 입력

 

  • 각 버튼을 더블클릭하여 이벤트를 생성한 후 코드를 입력한다.
using Basler.Pylon;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace BaslerChunkData
{
    public partial class Form1 : Form
    {
        private Camera camera;
        private PixelDataConverter converter;

        public Form1()
        {
            InitializeComponent();
            camera = new Camera();
            camera.StreamGrabber.ImageGrabbed += StreamGrabber_ImageGrabbed;
            converter = new PixelDataConverter();
        }
        private void BtnOpen_Click(object sender, EventArgs e)
        {
            OpenCamera();
            camera.Parameters[PLCamera.ChunkModeActive].SetValue(true);
            camera.Parameters[PLCamera.ChunkSelector].SetValue(PLCamera.ChunkSelector.Framecounter);
            camera.Parameters[PLCamera.ChunkEnable].SetValue(true);
        }

        private void BtnGrab_Click(object sender, EventArgs e)
        {
            camera.Parameters[PLCamera.AcquisitionMode].SetValue(PLCamera.AcquisitionMode.SingleFrame);
            camera.StreamGrabber.Start(1, GrabStrategy.OneByOne, GrabLoop.ProvidedByStreamGrabber);
        }

        private void BtnClose_Click(object sender, EventArgs e)
        {
            camera.Parameters[PLCamera.ChunkModeActive].SetValue(false);
            camera.Close();
        }

        private void StreamGrabber_ImageGrabbed(object sender, ImageGrabbedEventArgs e)
        {
            IGrabResult grabResult = e.GrabResult;
            long frameCounter = grabResult.ChunkData[PLChunkData.ChunkFramecounter].GetValue();
            BeginInvoke(new Action(() =>
            {
                textBox1.Text = frameCounter.ToString();
            }));
        }

        private void OpenCamera()
        {
            int timeOutMs = 1000;
            try
            {
                camera.Open();
            }
            catch (Exception)
            {
                System.Threading.Thread.Sleep(1000);
                if (!camera.IsConnected)
                {
                    camera.Close();
                    camera.Open(timeOutMs, TimeoutHandling.Return);
                }
            }
            camera.Parameters[PLTransportLayer.HeartbeatTimeout].TrySetValue(timeOutMs, IntegerValueCorrection.Nearest);
        }
    }
}

 

6.5 구문 설명

 

private void BtnOpen_Click(object sender, EventArgs e)
{
    OpenCamera(camera);
    camera.Parameters[PLCamera.ChunkModeActive].SetValue(true);
    camera.Parameters[PLCamera.ChunkSelector].SetValue(PLCamera.ChunkSelector.Framecounter);
    camera.Parameters[PLCamera.ChunkEnable].SetValue(true);
}
  • 구문이 필요없이 증가하기 때문에 기존 BtnOpen_Click이벤트에 들어가 있던 구문은 OpenCamera라는 이름의 함수로 빼서 설명한다.
  • ChunkModeActive를 true로 set하고 Selector에서 Framecounter를 선택하여 ChunkEnable을 true로 한다.
  • ChunkSelector에서 다른 data를 추가 선택하고 마지막에 ChunkEnable을 set하면 data가 추가된다.

 

private void BtnGrab_Click(object sender, EventArgs e)
{
    camera.Parameters[PLCamera.AcquisitionMode].SetValue(PLCamera.AcquisitionMode.SingleFrame);
    camera.StreamGrabber.Start(1, GrabStrategy.OneByOne, GrabLoop.ProvidedByStreamGrabber);
}
  • One shot Grab을 다르게 구현해보자
  • AcquisitionMode를 SingleFrame으로 설정하고 Start함수의 첫번째 매개변수에 maxImages 값을 1로 설정한다.
  • 이렇게 하면 Continue shot grab처럼 움직이되 maxImages값이 되면 자동으로 Stop()함수를 실행시킨다.
  • 만약 AcquisitionMode를 Continuous로 설정하게 되면 StreamGrabber_ImageGrabbed함수는 1번만 호출되지만 Framecounter가 1이 아닌 2가 증가할 때도 나온다. Stop()함수가 실행되기 전에 내부적으로 2번 그랩이 되는것으로 추정된다. maxImages를 증가해보면 counter가 더 많이 증가한채로 이벤트가 실행되는 것을 보게 된다.
private void BtnClose_Click(object sender, EventArgs e)
{
    camera.Parameters[PLCamera.ChunkModeActive].SetValue(false);
    camera.Close();
}

 

  • 카메라를 Close하기 전에 ChunkModeActive를 false로 한다.
private void StreamGrabber_ImageGrabbed(object sender, ImageGrabbedEventArgs e)
{
    IGrabResult grabResult = e.GrabResult;
    long frameCounter = grabResult.ChunkData[PLChunkData.ChunkFramecounter].GetValue();
    BeginInvoke(new Action(() =>
    {
        textBox1.Text = frameCounter.ToString();
    }));
}
  • grabResult.ChunkData Collection에 파라미터 name을 PLChunkData.ChunkFramecounter로 넣고 getvalue()를 하면 값이 long인 framecounter가 반환된다.

6.6 결과

5.1 개요

  • GigE 카메라 Open() 후에 예상치 못한 오류로 Close()를 하지 못했을 때 다시 Open()을 하게 되면 다음과 같은 오류가 발생한다
  • System.InvalidOperationException: 'Failed to open 'Basler xxx'. The device is controlled by another application. Err: An attempt was made to access an address location which is currently/momentary not accessible. (0xE1018006)
  • BaslerOneShotGrab 프로젝트의 BtnOpen_Click함수를 다시 수정하여 에러 처리를 하겠다.

5.2 코드 입력

 

private void BtnOpen_Click(object sender, EventArgs e)
{
    int timeOutMs = 1000;
    try
    {
        camera.Open();
    }
    catch (Exception)
    {
        System.Threading.Thread.Sleep(1000);
        if (!camera.IsConnected)
        {
            camera.Close();
            camera.Open(timeOutMs, TimeoutHandling.ThrowException);
        }
    }
    camera.Parameters[PLTransportLayer.HeartbeatTimeout].TrySetValue(timeOutMs, IntegerValueCorrection.Nearest);
    camera.Parameters[PLCamera.AcquisitionMode].SetValue(PLCamera.AcquisitionMode.Continuous);
}

 

5.3 구문 설명

 

catch (Exception)
{
    System.Threading.Thread.Sleep(1000);
    if (!camera.IsConnected)
    {
        camera.Close();
        camera.Open(timeOutMs, TimeoutHandling.ThrowException);
    }
}

 

  • Open()함수를 try catch구문으로 감싼 후에 System. InvalidOperationException 관련 Exception처리를 한다.
  • 그 다음 1000ms 정도 Open을 실행하고 있는 Thread를 sleep해서 딜레이를 준다
  • 이 딜레이는 환경에 따라 맞춰서 설정한다.
  • 딜레이 이후 camera가 Connect되지 않았다면 camera.Close()를 하고 다시 재 오픈을 한다.

 

camera.Parameters[PLTransportLayer.HeartbeatTimeout].TrySetValue(timeOutMs, IntegerValueCorrection.Nearest);

 

  • 해당 파라미터는 Basler의 HeartbeatTimeout을 설정하는 함수다
  • TrySetValue함수의 enum변수인 IntegerValueCorrection.Nearest는 timeOutMs값이 설정을 할수 없는 값이라면 유효한 값중에 가장 가까운 값으로 변경해서 입력된다
  • Heartbeat주기를 10000ms주면 10000ms안에 다시 Open()을 실행했을 때 Exception이 발생한다
  • 이 함수는 camera.Open()함수 바로 밑에 들어가는 것이 맞지만 최초 한번은 Open이 정상적으로 된다는 가정하에 try~catch문 밑에 출력 했으나 현장 상황상 최초 한번도 연결 안될 경우를 대비해 try와 catch구문 안에 조건문을 고려하여 따로 따로 넣어 주는것이 더 좋다고 볼수 있다.

'Basler' 카테고리의 다른 글

4. Multi Camera Grab  (0) 2024.02.15
3. Continue shot Grab  (0) 2024.02.13
2. One shot Grab  (0) 2024.02.11
1. c# 작업 환경 만들기  (0) 2024.02.08

4.1 Winform 프로젝트 만들기

  •  Basler 솔루션 안에 BaslerMultiCameraGrab이라는 이름으로 Windows Forms 앱 (.NET Framework) 프로젝트를 만들고 C#작업환경 만들기를 참조하여 Basler.Pylon.dll을 참조 추가한다.

2024.02.08 - [Basler] - 1. c# 작업 환경 만들기

 

1. c# 작업 환경 만들기

Basler 홈페이지에서 제공하는 Pylon Viewer를 설치한다 현재 내가 PC에 설치한 6.2.0 기준으로 (Pylon Viewer 설치 경로)\pylon 6\Development\Assemblies\Basler.Pylon\ 하위에 x64, x86폴더로 나눠져 있고 이중에 자기 os

machinevision-story.tistory.com

 

4.2 UI 디자인

 

  • 도구 상자에서 Button 8개와 PictureBox 2개를 드래그 하여 Form1에 위치 시킨다

 

 

  • button과 Name속성과 button의 Text속성을 아래 표와 같이 변경한다.
컨트롤 이름 속성
button1 Name BtnOpenCam0
Text Connect
button2 Name BtnGrabStartCam0
Text GrabStart
button3 Name BtnGrabStopCam0
Text GrabStop
button4 Name BtnCloseCam0
Text Disconnect
button5 Name BtnOpenCam1
Text Connect
button6 Name BtnGrabStartCam1
Text GrabStart
button7 Name BtnGrabStopCam1
Text GrabStop
button8 Name BtnCloseCam1
Text Disconnect

 

4.3 코드 입력

 

  • 각 버튼을 더블클릭하여 이벤트를 생성한 후 코드를 입력한다.
using Basler.Pylon;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace BaslerMultiCameraGrab
{
    public partial class Form1 : Form
    {
        List<ICamera> cameras = new List<ICamera>();
        private PixelDataConverter converter = new PixelDataConverter();
        public Form1()
        {
            InitializeComponent();
            List<ICameraInfo> cameraInfos = CameraFinder.Enumerate();
            for (int i = 0; i < cameraInfos.Count; i++)
            {
                Camera camera = new Camera(cameraInfos[i]);
                camera.StreamGrabber.ImageGrabbed += StreamGrabber_ImageGrabbed;
                camera.StreamGrabber.UserData = i;
                cameras.Add(camera);
            }
        }

        private void BtnOpenCam0_Click(object sender, EventArgs e)
        {
            cameras[0].Open();
            cameras[0].Parameters[PLCamera.AcquisitionMode].SetValue(PLCamera.AcquisitionMode.Continuous);
        }

        private void BtnGrabStartCam0_Click(object sender, EventArgs e)
        {
            cameras[0].StreamGrabber.Start(GrabStrategy.OneByOne, GrabLoop.ProvidedByStreamGrabber);
        }

        private void BtnGrabStopCam0_Click(object sender, EventArgs e)
        {
            cameras[0].StreamGrabber.Stop();
        }

        private void BtnCloseCam0_Click(object sender, EventArgs e)
        {
            cameras[0].Close();
        }

        private void BtnOpenCam1_Click(object sender, EventArgs e)
        {
            cameras[1].Open();
            cameras[1].Parameters[PLCamera.AcquisitionMode].SetValue(PLCamera.AcquisitionMode.Continuous);
        }

        private void BtnGrabStartCam1_Click(object sender, EventArgs e)
        {
            cameras[1].StreamGrabber.Start(GrabStrategy.OneByOne, GrabLoop.ProvidedByStreamGrabber);
        }

        private void BtnGrabStopCam1_Click(object sender, EventArgs e)
        {
            cameras[1].StreamGrabber.Stop();
        }

        private void BtnCloseCam1_Click(object sender, EventArgs e)
        {
            cameras[1].Close();
        }

        private void StreamGrabber_ImageGrabbed(object sender, ImageGrabbedEventArgs e)
        {
            IStreamGrabber cam = sender as IStreamGrabber;
            int camIndex = (int)cam.UserData;
            PictureBox pictureBox = null;
            if (camIndex == 0)
            {
                pictureBox = pictureBox1;
            }
            if (camIndex == 1)
            {
                pictureBox = pictureBox2;
            }
            IGrabResult grabResult = e.GrabResult;
            if (grabResult.GrabSucceeded)
            {
                Bitmap bitmap = ConvertResultToBitmap(grabResult);
                if (InvokeRequired)
                {
                    BeginInvoke(new Action(() =>
                    {
                        Bitmap bitmapOld = pictureBox.Image as Bitmap;
                        pictureBox.Image = bitmap;
                        if (bitmapOld != null)
                        {
                            bitmapOld.Dispose();
                        }
                    }));
                }
            }
        }

        private Bitmap ConvertResultToBitmap(IGrabResult grabResult)
        {
            Bitmap bitmap = new Bitmap(grabResult.Width, grabResult.Height, PixelFormat.Format32bppRgb);
            BitmapData bmpData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadWrite, bitmap.PixelFormat);
            IntPtr ptrBmp = bmpData.Scan0;
            converter.OutputPixelFormat = PixelType.BGRA8packed;
            converter.Convert(ptrBmp, bmpData.Stride * bitmap.Height, grabResult);
            bitmap.UnlockBits(bmpData);
            return bitmap;
        }
    }
}

 

4.4 구문 설명

 

List<ICameraInfo> cameraInfos = CameraFinder.Enumerate();
  • 카메라가 2대 이상일 경우 CameraFinder를 사용하면 보다 편리하게 ICameraInfo 리스트를 얻을 수 있다.
  • 현재 접속되어 있는 카메라를 받아오는 함수이며 특정 Device 타입만 불러오고 싶다면 DeviceType이라는 static 클래스를 매개변수로 넣어주면 해당 타입만 받아올 수 있다. (ex. GigE, Usb ..)
for (int i = 0; i < cameraInfos.Count; i++)
{
    Camera camera = new Camera(cameraInfos[i]);
    camera.StreamGrabber.ImageGrabbed += StreamGrabber_ImageGrabbed;
    camera.StreamGrabber.UserData = i;
    cameras.Add(camera);
}
  • Camera 클래스 생성자에 ICameraInfo 변수를 넣으면 특정 카메라 인스턴스를 생성할 수 있다.
  • 반복문을 돌려서 List<Camera> 클래스에 Add하는 구문이다.
  • UserData 항목은 StreamGrabber_ImageGrabbed 함수내부에서 sender인 카메라를 구분하기 위한 Index역할이다.

 

<StreamGrabber_ImageGrabbed>

IStreamGrabber cam = sender as IStreamGrabber;
int camIndex = (int)cam.UserData;
PictureBox pictureBox = null;
if (camIndex == 0)
{
    pictureBox = pictureBox1;
}
if (camIndex == 1)
{
    pictureBox = pictureBox2;
}
  • 앞 장의 StreamGrabber_ImageGrabbed함수와 구조는 동일하나 카메라 여러대가 하나의 이벤트 함수를 사용하기 때문에 어떤 카메라에서 발생한 이벤트인지 알기 위해서 매개변수인 sender의 UserData를 camera index로 참조한다.
  • 앞서 Camera 인스턴스를 생성하는 구문에서 넣어둔 UserData가 사용된다.
  • UserData를 원래 타입이었던 int로 형변환 한 후 인덱스가 0,1일때 해당 카메라가 연결되는 picturebox를 할당해서 Image를 넣는다.
IGrabResult grabResult = e.GrabResult;
if (grabResult.GrabSucceeded)
{
    Bitmap bitmap = ConvertResultToBitmap(grabResult);
    if (InvokeRequired)
    {
        BeginInvoke(new Action(() =>
        {
            Bitmap bitmapOld = pictureBox.Image as Bitmap;
            pictureBox.Image = bitmap;
            if (bitmapOld != null)
            {
                bitmapOld.Dispose();
            }
        }));
    }
}
  • IGrabResult를 Bitmap으로 바꾸는 구문은 함수 ConvertResultToBitmap()으로 빼고 진행해 보았다.
  • 나머지는 앞의 글들과 같다.

4.5 결과

 

'Basler' 카테고리의 다른 글

5. Reconnect Camera  (1) 2024.02.16
3. Continue shot Grab  (0) 2024.02.13
2. One shot Grab  (0) 2024.02.11
1. c# 작업 환경 만들기  (0) 2024.02.08

3.1 Winform 프로젝트 만들기

  •  Basler 솔루션 안에 BaslerContinueShotGrab이라는 이름으로 Windows Forms 앱 (.NET Framework) 프로젝트를 만들고 C#작업환경 만들기를 참조하여 Basler.Pylon.dll을 참조 추가한다.

2024.02.08 - [Basler] - 1. c# 작업 환경 만들기

 

1. c# 작업 환경 만들기

Basler 홈페이지에서 제공하는 Pylon Viewer를 설치한다 현재 내가 PC에 설치한 6.2.0 기준으로 (Pylon Viewer 설치 경로)\pylon 6\Development\Assemblies\Basler.Pylon\ 하위에 x64, x86폴더로 나눠져 있고 이중에 자기 os

machinevision-story.tistory.com

 

3.2 UI 디자인

  • 도구 상자에서 Button 4개와 PictureBox 1개를 드래그 하여 Form1에 위치 시킨다

  • button과 Name속성과 button의 Text속성을 아래 표와 같이 변경한다.
컨트롤 이름 속성
button1 Name BtnOpen
Text Connect
button2 Name BtnGrabStart
Text GrabStart
button3 Name BtnGrabStop
Text GrabStop
button4 Name BtnClose
Text Disconnect

 

3-3. 코드 입력

 

  • 각 버튼을 더블클릭하여 이벤트를 생성한 후 코드를 입력한다.
using Basler.Pylon;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace BaslerContinueShotGrab
{
    public partial class Form1 : Form
    {
        private Camera camera;
        private PixelDataConverter converter;

        public Form1()
        {
            InitializeComponent();
            camera = new Camera();
            camera.StreamGrabber.ImageGrabbed += StreamGrabber_ImageGrabbed;
            converter = new PixelDataConverter();
        }

        private void StreamGrabber_ImageGrabbed(object sender, ImageGrabbedEventArgs e)
        {
            IGrabResult grabResult = e.GrabResult;
            if (grabResult.GrabSucceeded)
            {
                Bitmap bitmap = new Bitmap(grabResult.Width, grabResult.Height, PixelFormat.Format32bppRgb);
                BitmapData bmpData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadWrite, bitmap.PixelFormat);
                IntPtr ptrBmp = bmpData.Scan0;
                converter.OutputPixelFormat = PixelType.BGRA8packed;
                converter.Convert(ptrBmp, bmpData.Stride * bitmap.Height, grabResult);
                bitmap.UnlockBits(bmpData);
                if (InvokeRequired)
                {
                    BeginInvoke(new Action(() =>
                    {
                        Bitmap bitmapOld = pictureBox1.Image as Bitmap;
                        pictureBox1.Image = bitmap;
                        if (bitmapOld != null)
                        {
                            bitmapOld.Dispose();
                        }
                    }));
                }
            }
        }

        private void BtnOpen_Click(object sender, EventArgs e)
        {
            camera.Open();
            camera.Parameters[PLCamera.AcquisitionMode].SetValue(PLCamera.AcquisitionMode.Continuous);
        }

        private void BtnGrabStart_Click(object sender, EventArgs e)
        {
            camera.StreamGrabber.Start(GrabStrategy.OneByOne, GrabLoop.ProvidedByStreamGrabber);
        }

        private void BtnGrabStop_Click(object sender, EventArgs e)
        {
            camera.StreamGrabber.Stop();
        }

        private void BtnClose_Click(object sender, EventArgs e)
        {
            camera.Close();
        }
    }
}

 

3.4 구문 설명

 

camera.StreamGrabber.ImageGrabbed += StreamGrabber_ImageGrabbed;
  • OneShotGrab과 달리 이벤트를 받아서 구현해보자
  • 대부분의 프로젝트에서는 이벤트로 구현하는 경우가 더 많기때문에 자주 쓰이게 되는 이벤트다.
  • ImageGrabbed 이벤트는 카메라의 이미지 취득이 완료되면 발생한다.

 

if (InvokeRequired)
{
    BeginInvoke(new Action(() =>
    {
        Bitmap bitmapOld = pictureBox1.Image as Bitmap;
        pictureBox1.Image = bitmap;
        if (bitmapOld != null)
        {
            bitmapOld.Dispose();
        }
    }));
}
  • StreamGrabber_ImageGrabbed 함수 내부는 UI쓰레드와 다른 쓰레드로 동작한다
  • 그래서 OneShotGrab과 다르게 비동기 Invoke함수를 이용해서 UI쓰레드에서 bitmap을 pictureBox1에 넣어 처리한다.
private void BtnOpen_Click(object sender, EventArgs e)
{
    camera.Open();
    camera.Parameters[PLCamera.AcquisitionMode].SetValue(PLCamera.AcquisitionMode.Continuous);
}
  • camera.Parameters 프로퍼티
    • 바슬러 카메라의 전반적인 프로퍼티들을 설정할 수 있는 IParameterCollection 인터페이스
    • 다양한 struct를 IEnumerable<>로 받아서 GetValue(), SetValue()로 제어할 수 있다.
    • PLCamera.AcquisitionMode를 Continuous로 하면 그랩 함수를 한번 실행했을 때 Stop할 때까지 연속 그랩한다.

나머지 부분은 OneShotGrab과 동일하다

 

3.5 결과

 

  • Connect > Grab Start > Grab Stop > Disconnect

'Basler' 카테고리의 다른 글

5. Reconnect Camera  (1) 2024.02.16
4. Multi Camera Grab  (0) 2024.02.15
2. One shot Grab  (0) 2024.02.11
1. c# 작업 환경 만들기  (0) 2024.02.08

2.1 Winform 프로젝트 만들기

  •  Basler 솔루션 안에 BaslerOneShotGrab이라는 이름으로 Windows Forms 앱 (.NET Framework) 프로젝트를 만들고 C#작업환경 만들기를 참조하여 Basler.Pylon.dll을 참조 추가한다.

2024.02.08 - [Basler] - 1. c# 작업 환경 만들기

 

1. c# 작업 환경 만들기

Basler 홈페이지에서 제공하는 Pylon Viewer를 설치한다 현재 내가 PC에 설치한 6.2.0 기준으로 (Pylon Viewer 설치 경로)\pylon 6\Development\Assemblies\Basler.Pylon\ 하위에 x64, x86폴더로 나눠져 있고 이중에 자기 os

machinevision-story.tistory.com

 

2.2 UI 디자인

 

  • 도구 상자에서 Button 3개와 PictureBox 1개를 드래그 하여 Form1에 위치 시킨다

 

  • button과 Name속성과 button의 Text속성을 아래 표와 같이 변경한다.
컨트롤 이름 속성
button1 Name BtnOpen
Text Connect
button2 Name BtnGrab
Text Grab
button3 Name BtnClose
Text Disconnect

 

 

2.3 코드 입력

 

  • BtnOpen, BtnGrab, BtnClose를 더블클릭하여 이벤트를 생성한 후 코드를 입력한다.
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Windows.Forms;
using Basler.Pylon;


namespace BaslerOneShotGrab
{
    public partial class Form1 : Form
    {
        private Camera camera;
        private PixelDataConverter converter;

        public Form1()
        {
            InitializeComponent();
            camera = new Camera();
            converter = new PixelDataConverter();
        }

        private void BtnOpen_Click(object sender, EventArgs e)
        {
            camera.Open();
        }

        private void BtnGrab_Click(object sender, EventArgs e)
        {
            camera.StreamGrabber.Start();
            IGrabResult grabResult = camera.StreamGrabber.RetrieveResult(5000, TimeoutHandling.Return);
            if (grabResult.GrabSucceeded)
            {
                Bitmap bitmap = new Bitmap(grabResult.Width, grabResult.Height, PixelFormat.Format32bppRgb);
                BitmapData bmpData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadWrite, bitmap.PixelFormat);
                IntPtr ptrBmp = bmpData.Scan0;
                converter.OutputPixelFormat = PixelType.BGRA8packed;
                converter.Convert(ptrBmp, bmpData.Stride * bitmap.Height, grabResult);
                bitmap.UnlockBits(bmpData);

                Bitmap bitmapOld = pictureBox1.Image as Bitmap;
                pictureBox1.Image = bitmap;
                if (bitmapOld != null)
                {
                    // Dispose the bitmap.
                    bitmapOld.Dispose();
                }
            }
            camera.StreamGrabber.Stop();
        }

        private void BtnClose_Click(object sender, EventArgs e)
        {
            camera.Close();
        }
    }
}

 

2.4 구문 설명

camera = new Camera();
  • 카메라의 인스턴스를 생성한다.
  • 매개변수를 넣지 않으면 첫번째 장치를 선택해서 생성한다.

 

camera.Open();
  • 카메라를 연결한다.

 

camera.StreamGrabber.Start();
  • 이미지 취득을 시작한다.

 

IGrabResult grabResult = camera.StreamGrabber.RetrieveResult(5000, TimeoutHandling.ThrowException);
  • 그랩이 완료 될 때까지 대기한 후 그랩 결과를 반환하는 함수다.
  • 첫번째 매개변수 : 그랩 완료 타임 아웃 변수, 단위 ms (ex. 5000이면 5000ms이후 그랩이 완료되지 않으면 event발생)
  • 두번째 매개변수 : 그랩 타임 아웃이 지난 후 발생한 이벤트 처리
    • TimeoutHandling.Return : 반환 값을 null처리하고 완료한다.
    • TimeoutHandling.ThrowException : 예외를 발생시킨다.

 

if (grabResult.GrabSucceeded)
  • 그랩이 성공적으로 완료되면 반환값인 IGrabResult의 GrabSucceeded값이 true가 된다.

 

Bitmap bitmap = new Bitmap(grabResult.Width, grabResult.Height, PixelFormat.Format32bppRgb);
                BitmapData bmpData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadWrite, bitmap.PixelFormat);
                IntPtr ptrBmp = bmpData.Scan0;
  • 이 구문은 일반적으로 많이 쓰이는 구문으로 Bitmap에서 비트맵 픽셀 데이터의 포인터 주소를 가져올 수 있다.
  • bitmap lockbits를 구글링하면 자세한 정보를 얻을 수 있다.

 

private PixelDataConverter converter;
converter = new PixelDataConverter();
converter.OutputPixelFormat = PixelType.Mono8;
converter.Convert(ptrBmp, bmpData.Stride * bitmap.Height, grabResult);
  • PixelDataConverter는 Basler.Pylon.dll이 들어있는 클래스로써 소스이미지를 변환하여 새 이미지를 만들 때 쓰인다.
  • Convert() : 그랩 데이터를 새로 만든 Bitmap에 복사하는 함수
    • 첫번째 매개변수 : 결과 bitmap의 픽셀 데이터 포인터
    • 두번째 매개변수 : 픽셀 데이터의 크기 ( 결과 bitmap의 stride * height )
    • 세번째 매개변수 : 그랩 데이터

 

bitmap.UnlockBits(bmpData);
  • lockbits함수를 사용하여 lock걸린 메모리 영역을 unlock하는 함

 

Bitmap bitmapOld = pictureBox1.Image as Bitmap;
                pictureBox1.Image = bitmap;
                if (bitmapOld != null)
                {
                    bitmapOld.Dispose();
                }
  • Bitmap을 pictureBox1에 넣기 전에 기존에 pictureBox1에 있던 Bitmap을 빼서 Dispose하는 구문
  • bitmap을 dispose하지 않고 새 bitmap을 넣게 되면 메모리 누수가 일어난다.

 

camera.StreamGrabber.Stop();
  • 그랩을 멈춘다.

 

camera.Close();
  • 카메라를 닫는 함수.
  • 종료하기 전에 항상 호출해야 한다.

2.5 결과

 Connect → Grab → Disconnect

'Basler' 카테고리의 다른 글

5. Reconnect Camera  (1) 2024.02.16
4. Multi Camera Grab  (0) 2024.02.15
3. Continue shot Grab  (0) 2024.02.13
1. c# 작업 환경 만들기  (0) 2024.02.08

Basler 홈페이지에서 제공하는 Pylon Viewer를 설치한다

 

현재 내가 PC에 설치한 6.2.0 기준으로 

(Pylon Viewer 설치 경로)\pylon 6\Development\Assemblies\Basler.Pylon\ 하위에 x64, x86폴더로 나눠져 있고

이중에 자기 os에 맞는 폴더를 들어가보면 "Basler.Pylon.dll"이 있다

앞으로 나올 프로젝트에서는 모두 이 dll을 참조한다는 가정하에 진행한다.

 

 Winform 프로젝트 만들기

 

1. 새 프로젝트 만들기에서 Windows Forms 앱 (.NET Framework)로 선택하고 다음 클릭

 

 

2. 새 프로젝트 구성에서 프로젝트 이름과 위치, 솔루션 이름을 적당히 정하고

프레임워크 부분을 .NET Framework 4.0 이상으로 선택한 후 만들기 버튼 클릭

(필자는 4.7.2로 진행 중)

 

3. 프로젝트가 만들어졌다면 솔루션 탐색기 창의 참조에 프로젝트안에 있는 참조에 마우스 우클릭 후 참초 추가 클릭

4. 참조 관리자 창이 열리면 왼쪽 찾아보기 메뉴 클릭 후 오른쪽 하단의 찾아보기 클릭

5. 앞서 말한 Basler.Pylon.dll이 위치한 경로에 가서 해당 파일을 선택한 후 추가 버튼 클릭 후 확인 버튼 클릭

 

6. 해당 dll이 정상적으로 프로젝트에 참조됐다면 다음과 같이 보이게 된다.

 

7. 추가하고 나면 다음과 같은 경고가 보이게 된다. 플랫폼이 32비트 기본사용이라 나오는 경고다.


    프로젝트 마우스 우클릭 > 속성 > 빌드 창을 열어서 32비트 기본 사용 체크 풀고 Any CPU를 x64로 바꾸면 준비 끝

'Basler' 카테고리의 다른 글

5. Reconnect Camera  (1) 2024.02.16
4. Multi Camera Grab  (0) 2024.02.15
3. Continue shot Grab  (0) 2024.02.13
2. One shot Grab  (0) 2024.02.11

Vpro 지원 카메라

 

  • 지원 카메라 여부는 코그넥스 홈페이지 내 지원 페이지에서 확인 가능하다.

  • 현재 가지고 있는 카메라가 지원 목록에 있다면 CogframeGrabber 클래스에서 인식이 가능하며
    목록에 없는 카메라도 간혹 CogframeGrabbers 클래스에 인식하는 경우가 있지만 카메라 제어에 예상치 못한 문제가 생길 수 있다.

 ICogImage 취득

  • 다음은 CogframeGrabbers 클래스에 첫번째 인식 된 카메라를 8비트 흑백 이미지로 출력하는 소스다.
  • 사용하는 카메라가 칼라라면 지원 videoformat중 원하는 format으로 설정해서 Create하면 된다.

  • StartAcquire 함수 실행 후 카메라가 동작을 완료하면 Complete이벤트가 발생하고
    CompleteAcquireEX함수가 리턴하는 ICogImage를 이용하여 로직을 구현하면 된다.

  • VisionPro는 기본적으로 함수 입력 이미지가 ICogImage로 되어 있다.

  • 여러가지 이미지 포멧들을 ICogImage로 컨버트해서 사용하거나 카메라에서 직접 ICogImage로 취득해서 사용한다.

using Cognex.VisionPro;
using System.Windows.Forms;

namespace WindowsFormsApp1
{
    public partial class Form1 : Form
    {
        private ICogAcqFifo acqFifo;

        public Form1()
        {
            InitializeComponent();
            InitFramegrabbers();

        }

        private void InitFramegrabbers()
        {
            CogFrameGrabbers grabbers = new CogFrameGrabbers();
            if(grabbers.Count > 0)
            {
                ICogFrameGrabber gb = grabbers[0];
                CogStringCollection videoFormat = gb.AvailableVideoFormats;
                acqFifo = gb.CreateAcqFifo(videoFormat[0], CogAcqFifoPixelFormatConstants.Format8Grey, 0, true);
                acqFifo.Complete += AcqFifo_Complete;
            }
        }

        private void AcqFifo_Complete(object sender, CogCompleteEventArgs e)
        {
            ICogAcqInfo acqInfo = new CogAcqInfo();
            ICogImage resultImage = acqFifo.CompleteAcquireEx(acqInfo);
        }

        private void OneShot()
        {
            acqFifo.StartAcquire(); 
        }
    }
}

 

Cognex Insight에서는 Serial Native Commands라는 명령어 모음으로 Tcp/ip 및 Serial 통신을 이용해서 값을 주고 받습니다

 

프로젝트에서 많이 쓰이는 것은 장비 PLC나 보드와의 Serial통신이나 PC프로그램과의 Tcp 통신이 있겠죠

 

그 커맨드 중에 가장 보편적으로 쓰이는 명령어에 대해 알아보겠습니다


 카메라 접속하기

 

텔넷으로 카메라 ip에 접속하면 로그인 화면이 출력됩니다

 

Insight Explorer 상에 설정된 사용자 접근 설정 계정 중 하나로 로그인 합니다

 

로그인이 정상적으로 되면 "User Logged In" 이라는 메세지가 출력됩니다

 

( 기본 설정으로 시작하셨다면 ID : admin , Password는 없으므로 그냥 엔터치면 됩니다 )

 

 

 

 

 트리거 신호 보내기

A0셀을 더블클릭하여 <그림3> 과 같이 Property Sheet를 들어가서 Trigger 를 Manual로 변경합니다

 

Insight 도움말에서 Set Event 를 찾아 보면 <그림4> 와 같은 Inputs 구문을 확인할 수 있습니다

SE 뒤에 8을 붙이면 이미지 한장을 취득하고 스프레드 시트를 업데이트 합니다

그림 4

 

 

SE8 명령을 보낸 후 정상적으로 동작이 완료 되면 Outputs 구문의 1이 리턴 됩니다

 

 

 소프트웨어 온/오프라인

 

장비 동작 중에 카메라의 온/오프를 제어해야 하는 경우에 쓰며

장비가 Explorer상에서 온라인이 되어야만 명령어가 동작합니다

Set Online I/O 도움말

온라인이 아닌 경우에 명령어를 보냈을 경우 -5가 리턴됩니다

 

온라인일 경우에 SO0 명령을 보낸 경우 1이 리턴되면서 인사이트 온/오프 확인 창에 메세지가 나타납니다

 

다시 SO1 명령을 보내면 1이 리턴되면서 인사이트 창에 정상적으로 온라인 메세지가 나타납니다

'Cognex > Insight-Explorer' 카테고리의 다른 글

cvsinsightdisplay 셀 값 가져오기  (0) 2019.06.03
cvsinsightdisplay 접속하기  (2) 2019.06.03

+ Recent posts