CAFE

영상처리및제어

샘플-Basler GigE 또는 USB3.0 카메라 영상 캡쳐하기 (OpenCV 사용)

작성자한창호|작성시간16.01.12|조회수14,685 목록 댓글 0

 Basler ace GigE 카메라와 OpenCV 2.4.11을 이용하여 영상을 캡쳐하는 프로그램을 작성해 보자.

 

GigE 카메라                        USB 3.0 카메라                                 CameraLink 카메라

 

다음 그림은 USB 3.0 케이블이다. USB 안쪽이 파란색으로 구분을 한다. USB 2.0은 검은색이다.    

 

* Pylon 라이브러리 다운로드 및 설치

 

- Pylon Lib 다운로드 사이트: https://www2.baslerweb.com/en/downloads/software-downloads/

 

- 직접 다운로드 (2023.11.02):  pylon 7.4.0 Camera Software Suite Windows  

 

- 설치시 DeveloperUSB를 선택한다. (개발자 모드로 설치해야 라이브러리를 사용 가능하다.)

 

위 라이브러리를 설치하여 PylonView로 카메라가 동작을 하는지 확인해야 한다. 

바슬러카메라 영상이 한쪽으로 치우쳤을 경우 다음과 같이 Pylon 설정부분에서 OffsetX, OffsetY를 조절한다.

 

* Basler 카메라 (Thread 사용) 를 MFC (Visual Studio 2022)로 직접 작성해보자.

단계코드 작성 내용
Visual Studio 2022대화상자 (Dialog base)로 프로젝트 생성한다.



카메라 화면:  Picture Control,  IDC_CAM_VIEW,   변수추가: m_CamView
시작버튼:      Cam Start,  IDC_CAM_START
정지버튼:      Cam Stop,  IDC_CAM_STOP
OpenCV 설치참고: https://cafe.daum.net/smhan/cczU/61
Pylon 7 Lib 설치

프로젝트 속성 설정
Pylon7 Lib 다운로드:   pylon 7.4.0 Camera Software Suite Windows  
Opencv 480 다운로드: opencv-4.8.0-windows.exe

구성속성->VC++ 디렉터리->포함 디렉터리
    $(PYLON_DEV_DIR)\include
    C:\opencv480\build\include

구성속성->VC++ 디렉터리->라이브러리 디렉터리

    $(PYLON_DEV_DIR)\lib\x64
    C:\opencv480\build\x64\vc16\lib

구성속성->디버깅->환경
    PATH=%PATH%;C:\opencv480\build\x64\vc16\bin;

구성속성->링커->입력->추가 종속성
    opencv_world480d.lib
baslerCam2023Dlg.h

함수 및 변수 선언
#include <opencv2/opencv.hpp>
#include <pylon/PylonIncludes.h>

using namespace Pylon;
using namespace GenApi;
using namespace cv;


UINT ThreadImageCaptureFunc(LPVOID param);     // 쓰레드 함수

void FillBitmapInfo(BITMAPINFO* bmi, int width, int height, int bpp, int origin);
void DisplayImage(CDC* pDC, CRect rect, Mat& srcimg);

class CbaslerCam2023Dlg  : public CDialogEx { 

public:
    BOOL m_bThreadFlag;                    // 쓰레드 루프 돌기

    CInstantCamera *m_pCamera;          // Basler Camera
    CGrabResultPtr m_ptrGrabResult;      // grab result data 받기
    Mat m_Image;                              // 추가하기
...
}
Pylon 초기화using namespace std;


BOOL CbaslerCam2023Dlg::OnInitDialog()
{
    ....
    // TODO: 여기에 추가 초기화 작업을 추가합니다.

    PylonInitialize();

    // Get the transport layer factory.
    CTlFactory& tlFactory = CTlFactory::GetInstance();

    // Get all attached devices and exit application if no device is found.
    DeviceInfoList_t devices;
    if (tlFactory.EnumerateDevices(devices) == 0) {
        MessageBox(L"Basler Camera가 연결되지 않았습니다.");
    }
    else {
        // create device
        //IPylonDevice *pDevice = TlFactory.CreateDevice(lstDevices[0]);
        // Create an instant camera object with the camera device found first.
        m_pCamera = new CInstantCamera(CTlFactory::GetInstance().CreateFirstDevice());

        try {
            // 카메라 파리미터 설정하기
            m_pCamera->Open();

            INodeMap& nodemap = m_pCamera->GetNodeMap();
            // Get the integer nodes describing the AOI.
            CIntegerPtr offsetX(nodemap.GetNode("OffsetX"));
            CIntegerPtr offsetY(nodemap.GetNode("OffsetY"));
            CIntegerPtr width(nodemap.GetNode("Width"));
            CIntegerPtr height(nodemap.GetNode("Height"));

            // GenApi has some convenience predicates to check this easily.
            int new_width = 1024;
            int new_height = 624;    // 768시 error 발생
            if (IsWritable(width))   width->SetValue(new_width);
            if (IsWritable(height))  height->SetValue(new_height);
            if (IsWritable(offsetX)) offsetX->SetValue(new_width / 2);
            if (IsWritable(offsetY)) offsetY->SetValue(new_height / 2);

            // 카메라 정보 출력
            CString info;
            info.Format(_T("Found camera!\n<%s>\nSize X: %d\nSize Y: %d"),
                CString(m_pCamera->GetDeviceInfo().GetModelName()),
                width->GetValue(), height->GetValue());
            AfxMessageBox(info);

            m_pCamera->Close();
        }
        catch (GenICam::GenericException& e)  {
            // Error handling
            CString strTrace;
            strTrace.Format(_T("Open_Camera-Generic Exception : %s\n"), (CString)e.GetDescription());
            AfxMessageBox(strTrace);
            return FALSE;
        }
    }

    return TRUE;  // 포커스를 컨트롤에 설정하지 않으면 TRUE를 반환합니다.
}
baslerCam2023Dlg.cpp

맨 밑에

쓰레드함수 추가


UINT ThreadImageCaptureFunc(LPVOID param)
{
    CbaslerCam2023Dlg* pDlg = (CbaslerCam2023Dlg*)param;
    if (pDlg->m_pCamera == NULL) return 0;

    while (pDlg->m_bThreadFlag) {
        try {
            if (pDlg->m_pCamera->IsGrabbing()) {
                // Wait for an image and then retrieve it. A timeout of 5000 ms is used.
                pDlg->m_pCamera->RetrieveResult(5000, pDlg->m_ptrGrabResult,
                      TimeoutHandling_ThrowException);

                if (pDlg->m_ptrGrabResult->GrabSucceeded()) {

                    // Color로 포맷을 변경할 경우
                    //CImageFormatConverter fc;
                    //fc.OutputPixelFormat = PixelType_RGB8packed;
                    //CPylonImage pylonImage;
                    //fc.Convert(pylonImage, pDlg->m_ptrGrabResult);
                    //Mat camImage = Mat(pDlg->m_ptrGrabResult->GetHeight(), 
                    //    pDlg->m_ptrGrabResult->GetWidth(), CV_8UC3,
                    //    (uint8_t*)pylonImage.GetBuffer());

                    // 카메라 이미지를 화면에 출력
                    pDlg->m_Image = Mat(pDlg->m_ptrGrabResult->GetHeight(),
                        pDlg->m_ptrGrabResult->GetWidth(), CV_8UC1, 
                        (uint8_t*) pDlg->m_ptrGrabResult->GetBuffer());

                    CRect rect;
                    CDC* pDC = pDlg->m_CamView.GetDC();       // 출력한 부분의 DC 얻기
                    pDlg->m_CamView.GetClientRect(rect);           // 출력할 영역 얻기
                    DisplayImage(pDC, rect, pDlg->m_Image );     // 화면에 그리기
                    pDlg->ReleaseDC(pDC);
                }
                else {
                    CString str;
                    str.Format(_T("Error: %d %d") , pDlg->m_ptrGrabResult->GetErrorCode(),
                         pDlg->m_ptrGrabResult->GetErrorDescription());
                    AfxMessageBox(str);
                    pDlg->m_bThreadFlag = false;
                }
            }
        }
        catch (GenICam::GenericException& e) {
            // Error handling.
            cerr << "An exception occurred." << e.GetDescription() << endl;
        }
    }

    return 0;
}


다음은 화면 출력 함수로 카페에서 참고하여 복사한다.  (https://cafe.daum.net/smhan/darS/2)

void FillBitmapInfo(BITMAPINFO* bmi, int width, int height, int bpp, int origin)
{
    ....
}

void DisplayImage( CDC* pDC, CRect rect, Mat& srcimg)
{
    ....
}
카메라 시작 버튼void CbaslerCam2023Dlg::OnBnClickedCamStart()
{
    if (m_pCamera == NULL) {
        MessageBox(L"Basler Camera를 연결 후 다시 실행시켜주세요.");
        return;
    }
    m_pCamera->StartGrabbing();
    m_bThreadFlag = TRUE;
    CWinThread *pThread = ::AfxBeginThread(ThreadImageCaptureFunc, this);
}
카메라 정지 버튼void CbaslerCam2023Dlg::OnBnClickedCamStop()
{
    if (m_pCamera == NULL) {
        MessageBox(L"Basler Camera를 연결 후 다시 실행시켜주세요.");
        return;
    }
    m_pCamera->StopGrabbing();
    m_bThreadFlag = FALSE;          // 쓰레드 정지 시킴
}
basler 종료시
메모리 삭제  
WM_DESTROY
void CbaslerCam2023Dlg::OnDestroy()
{
    CDialogEx::OnDestroy();

    PylonTerminate();    // Releases all pylon resources. 
    m_pCamera->StopGrabbing();
    m_bThreadFlag = FALSE;
    if (m_pCamera != NULL) delete m_pCamera;
}
영상 불러오기// 불러올때는 Cam 을 멈춘상태에서 불러와야 지워지지 않는다.

void CbaslerCam2023Dlg::OnBnClickedBmpLoad()
{
    wchar_t szFilter[] = _T("Image (*.BMP) | *.BMP;*.GIF;*.JPG | All Files(*.*)|*.*||");
    CFileDialog dlg(TRUE, _T("bmp"), _T("test"), OFN_HIDEREADONLY, szFilter);

    if (dlg.DoModal() == IDOK) {
        CRect rect;
        CStringA filename(dlg.GetPathName());
        m_Image = cvLoadImage(filename);
        // Invalidate(FALSE);
        CRect rect;
        CDC* pDC = m_CamView.GetDC();       // 출력한 부분의 DC 얻기
        m_CamView.GetClientRect(rect);           // 출력할 영역 얻기
        DisplayImage(pDC, rect, m_Image);          // 화면에 그리기
        ReleaseDC(pDC);
    }
}
영상 저장하기// 현재 캡쳐한 영상을 파일로 저장한다.
// Mat m_Image를 *.h 클래스에 선언한다.

void CbaslerCam2023Dlg::OnBnClickedBmpSave()
{
    wchar_t szFilter[] = _T("Image (*.BMP) | *.BMP;*.GIF;*.JPG | All Files(*.*)|*.*||");
    CFileDialog dlg(FALSE, _T("bmp"), _T("test"), OFN_HIDEREADONLY, szFilter);
    if (dlg.DoModal() == IDOK) {

        cvFlip(m_Image, m_Image, 0);  // 영상을 위/아래로 뒤집는다.
        CStringA filename(dlg.GetPathName());
        cvSaveImage(filename, m_Image);
    }
}

 

 

* GigE 카메라OpenCV 2.4.11로 작성한 프로그램 소스파일들

 

샘플 소스:  (Timer 사용)

 

샘플 소스: (Thread 사용, OpenCV 2.4.13)

     (떨림 현상을 제거하려면, thread()함수에서 Invalidate()함수를 제거하고 직접 영상을 출력합니다.)

 

 

Basler USB3.0 카메라와 Opencv 2.4.11을 이용해서 테스트를 해보았다.

 

샘플 Mono 소스: 

샘플 Color 소스:

 

 

 

 

 

다음검색
현재 게시글 추가 기능 열기

댓글

댓글 리스트
맨위로

카페 검색

카페 검색어 입력폼