Qt + OpenCV. New GigE Network Camera Access Interface Device Like CvCapture

    As Henry VIII told his next wife, “I won’t hold you for a long time ...”
    Fasting is a small extension of the previous article “Qt + OpenCV. Runtime and Widget for CvCapture (video capture devices). ”
    If you, dear reader, have managed to purchase a video camera, the support of which is not provided by the OpenCV library , and the methods for working with it as needed are not to be upset.
    First, we’ll study what they presented to us, or what they themselves, ignorant, bought.
    1. The GigE interface is supported by the SDK, which is freely available or delivered with the product. The first plus!
    2. The documentation is more or less meaningful. Lucky again!
    3. There are examples! Wow ... Plus!

    So, I became “lucky” on the pluses of this list, having got a Smartek Giganetix GC1921M camera
    . SDK methods work, but somehow ... The code is partially closed. The programmer level became clear from the code snippet
    ...
    if (m_selectedDevice->IsConnected()){
    			m_disconnectAct->setEnabled(true);
    			m_fwUpdateAct->setEnabled(true);
    }
    ...
    

    If you had a question, “What’s wrong with that?”, I won’t be able to send you to a Soviet university in a time machine, where you will be taken off the exam score. :)

    Yes, okay. We just need to connect, accept the stream and disconnect. Fortunately, examples are in place.

    Implementation options for your own video capture device.


    Thanks to the developers of the OpenCV library for the code distributed under the BSD license.
    We are talking about version 2.4.2.
    We will study part of the source code in the modules / highgui / src directory. As you can see, everything is simple. You can simply copy a similar module, for example cap_pvapi.cpp, to make cap_giganetix.cpp your own device, make the appropriate changes, make changes (new method and enum enumeration elements) to the precomp.hpp code and the corresponding directive files for cmake and run the build.
    This is the first method. The main disadvantage is that everything changes from version to version, and the reassembly of new releases is inevitable.
    There is also a more stable, if one may call it that, option - implementing your own CvCaptute for a new device compatible with the structure from OpenCV. The plus is that the developer puts all this canoe all his earnings in a separate library, which, according to the requirements of the dependencies, will load both the SDK on the new device and OpenCV.
    The minus, as always, is the presence of a “pig in a poke” - implementation on the side of the OpenCV developers of the hidden structure of CvCapture.
    Consider the last option.

    CvCapture type external video capture device library.

    First , the word was to ensure compatibility with macros, the values ​​of the enumerations of the source and header files of OpenCV.
    macros.hpp
    #ifndef MACROS_HPP
    #define MACROS_HPP
    #define QTGIG_HEARTBEAT_TIME (12000.0)
    #define QTGIG_MAX_WAIT_TIME (2.0)
    #define QTGIG_IMG_WAIT_TIME (3.0)
    #define CV_CAP_GIGANETIX 1300
    // GigE additional for highgui_c.h
    //enum {
    #define CV_CAP_PROP_GIGA_FRAME_SENS_WIDTH   40
    #define CV_CAP_PROP_GIGA_FRAME_SENS_HEIGH   41
    #define CV_CAP_PROP_GIGA_FRAME_WIDTH_MAX    42
    #define CV_CAP_PROP_GIGA_FRAME_HEIGH_MAX    43
    #define CV_CAP_PROP_GIGA_FRAME_OFFSET_X     44
    #define CV_CAP_PROP_GIGA_FRAME_OFFSET_Y     45
    //};
    //precomp.hpp double
    #define __BEGIN__ __CV_BEGIN__
    #define __END__  __CV_END__
    #define EXIT __CV_EXIT__
    #endif // MACROS_HPP
    


    Plot
    //precomp.hpp double
    #define __BEGIN__ __CV_BEGIN__
    #define __END__  __CV_END__
    #define EXIT __CV_EXIT__
    
    will lead the code to the rules for developing OpenCV modules . Do not go into a strange monastery with your charter!
    And so, we just added some properties to our device.
    Create wrapper methods for our camera’s SDK functions. This will minimize the changes in our code with the possible editing by developers of their own SDK. I think this is a good style.

    gige_wrapper.h
    
    #ifndef GIGE_WRAPPER_H
    #define GIGE_WRAPPER_H
    /**
      \module GIGA_WRAPPER
      \brief Smartek Giganetix Cameras wrapper
    */
    #include 
    namespace gigew {
    /*----------------------------------------------------------------------------*/
    /**
      \internal
      \fn bool gigew::wrprInitGigEVisionAPI();
      \brief Wrapper to GigEVisionAPI function gige::InitGigEVisionAPI ()
      \return true - success
      See \a gigew::wrprExitGigEVisionAPI
    */
    bool
    wrprInitGigEVisionAPI();
    /*----------------------------------------------------------------------------*/
    /**
      \internal
      \fn void gigew::wrprExitGigEVisionAPI()
      \brief Wrapper to GigEVisionAPI function gige::ExitGigEVisionAPI ()
      \return true -- success
      See \a gigew::wrprInitGigEVisionAPI
    */
    bool
    wrprExitGigEVisionAPI();
    // и так далее...
    } //namespace gigew
    #endif // GIGE_WRAPPER_H
    



    And, in fact, our device itself (cap_giganetix.h)
    #ifndef CAP_GIGANENIX_H
    #define CAP_GIGANENIX_H
    #include 
    #include "GigEVisionSDK.h"
    #include "../../common/macros.hpp"
    #include 
    #ifdef HAVE_GIGE_API
      #if !defined WIN32 && !defined _WIN32 && !defined _LINUX
      #define _LINUX
      #endif
      #if defined(_x64) || defined (__x86_64) || defined (_M_X64)
      #define _x64 1
      #elif defined(_x86) || defined(__i386) || defined (_M_IX86)
      #define _x86 1
      #endif
    /*----------------------------------------------------------------------------*/
    /**
      \internal
      \struct CvCapture
      \brief Copy OpenCV CvCapture internal release.
    */
    struct CvCapture
    {
        virtual ~CvCapture() {}
        virtual double getProperty(int) { return 0; }
        virtual bool setProperty(int, double) { return 0; }
        virtual bool grabFrame() { return true; }
        virtual IplImage* retrieveFrame(int) { return 0; }
        virtual int getCaptureDomain() { return CV_CAP_ANY; } // Return the type of the capture object: CV_CAP_VFW, etc...
    };
    /*----------------------------------------------------------------------------*/
    /**
      \internal
      \class CvCaptureCAM_Giganetix
      \brief Capturing video from camera via Smartec Giganetix GigEVisualSDK
    */
    class Q_DECL_EXPORT CvCaptureCAM_Giganetix : public CvCapture
    {
      public:
        CvCaptureCAM_Giganetix();
        virtual ~CvCaptureCAM_Giganetix();
        virtual bool open( int index );
        virtual void close();
        virtual double getProperty(int);
        virtual bool setProperty(int, double);
        virtual bool grabFrame();
        virtual IplImage* retrieveFrame(int);
        virtual int getCaptureDomain()
        {
            return CV_CAP_GIGANETIX;
        }
        bool  start ();
        bool  stop ();
      protected:
        void  init ();
        void  grabImage ();
        gige::IGigEVisionAPI  m_api;
        bool                  m_api_on;
        gige::IDevice         m_device;
        bool                  m_active;
        IplImage* m_raw_image;
        UINT32    m_rawImagePixelType;
        bool      m_monocrome;
    };
    /*----------------------------------------------------------------------------*/
    Q_DECL_EXPORT CvCapture* cvCreateCameraCapture_Giganetix( int index );
    /*----------------------------------------------------------------------------*/
    #endif
    #endif // CQTGIGEVISIONCAPTURE_H
    


    Please note that the ad struct CvCaptureis taken from the OpenCV source code (directory modules / highgui / src , file precomp.hpp ). Here it is, the bottleneck of the library!

    We write the implementation of the class and method cvCreateCameraCapture_Giganetix.
    Take the project archive from the link.
    I will only give the method code open:
    ...
    /*----------------------------------------------------------------------------*/
    bool
    CvCaptureCAM_Giganetix::open( int index )
    {
      bool b_ret = m_api_on;
      CV_FUNCNAME("CvCaptureCAM_Giganetix::open");
      __BEGIN__;
      if(b_ret)
        b_ret = m_api.IsValid ();
      if(b_ret )
      {
        m_api->FindAllDevices (QTGIG_MAX_WAIT_TIME);
        //TODO - serch device as DevicesList member
        gige::DevicesList DevicesList = m_api->GetAllDevices ();
        m_device = 0;
        b_ret = false;
        for (int i = 0; i < (int) DevicesList.size() && !b_ret; i++)
        {
          if((b_ret = i == index))
          {
            m_device = DevicesList[i];
            b_ret = m_device->Connect ();
            if(b_ret)
            {
              b_ret =
                    m_device->SetStringNodeValue("AcquisitionStatusSelector", "AcquisitionActive")
                    &&
                    m_device->SetStringNodeValue ("TriggerMode", "Off")
                    &&
                    m_device->SetStringNodeValue ("AcquisitionMode", "Continuous")
                    &&
                    m_device->SetIntegerNodeValue ("AcquisitionFrameCount", 20)
                    ;
            }
          }
        } // for
      }
      if(!b_ret)
      {
        CV_ERROR(CV_StsError, "Giganetix: Error cannot find camera\n");
        close ();
      } else {
        start ();
      }
      __END__;
      return b_ret;
    }
    ...
    

    It is shown how to use macros according to the programming style from OpenCV.

    We design the project file as a dynamically connected library with access to the SDK and OpenCV:
    #-----------------------------------------------------------
    TARGET = QtGigEVisionCapture
    TEMPLATE = lib
    #CONFIG += release
    #-----------------------------------------------------------
    DEFINES += QTGIGEVISION_LIBRARY \
      HAVE_GIGE_API
    #-----------------------------------------------------------
    SOURCES += \
        ../../common/QtGigEVision_global.cpp \
        cap_giganetix.cpp \
        gige_wrapper.cpp
    HEADERS +=\
        ../../common/QtGigEvision_global.h \
        ../../common/macros.hpp \
        cap_giganetix.h \
        gige_wrapper.h
    #-----------------------------------------------------------
    unix:!symbian: target.path = /usr/lib
    INSTALLS += target
    #-----------------------------------------------------------
    unix:!macx:!symbian: LIBS += -L/usr/local/lib/ -lGigEVisionSDK
    INCLUDEPATH += /usr/local/include/GigEVisionSDK/gige_cpp \
      /usr/local/include/GigEVisionSDK/gige_c
    DEPENDPATH += /usr/local/include/GigEVisionSDK/gige_cpp \
      /usr/local/include/GigEVisionSDK/gige_c
    #-----------------------------------------------------------
    unix: LIBS += -L/usr/lib/ -lopencv_core -lopencv_highgui
    INCLUDEPATH += /usr/include/opencv2/core \
      /usr/include/opencv2/highgui
    DEPENDPATH += /usr/include/opencv2/core \
      /usr/include/opencv2/highgui
    



    Under superuser privileges, in the / usr / lib directory we place links to the new library and ... proceed to testing.

    Test case.


    The code
    #include 
    #include "../../common/macros.hpp"
    #include 
    #include "cap_giganetix.h"
    void print_properties (CvCaptureCAM_Giganetix* cap)
    {
      if(cap) {
          printf("Device found.\n");
          printf("Sensor Width  = %d.\n", (int)cap->getProperty (CV_CAP_PROP_GIGA_FRAME_SENS_WIDTH));
          printf("Sensor Height = %d.\n", (int)cap->getProperty (CV_CAP_PROP_GIGA_FRAME_SENS_HEIGH));
          printf("Offset X      = %d.\n", (int)cap->getProperty (CV_CAP_PROP_GIGA_FRAME_OFFSET_X));
          printf("Offset Y      = %d.\n", (int)cap->getProperty (CV_CAP_PROP_GIGA_FRAME_OFFSET_Y));
          printf("Width         = %d.\n", (int)cap->getProperty (CV_CAP_PROP_FRAME_WIDTH));
          printf("Height        = %d.\n", (int)cap->getProperty (CV_CAP_PROP_FRAME_HEIGHT));
          printf("Frame Count   = %d.\n", (int)cap->getProperty (CV_CAP_PROP_FRAME_COUNT));
          printf("Gain          = %d.\n", (int)cap->getProperty (CV_CAP_PROP_GAIN));
      }
    }
    int main(int argc, char *argv[])
    {
      QApplication a(argc, argv);
      CvCapture* capture = cvCreateCameraCapture_Giganetix(0);
      CvCaptureCAM_Giganetix* cap = (CvCaptureCAM_Giganetix*)capture;
      int i_width, i_height, i_offX, i_offY;
      if(cap) {
        i_width = (int)capture->getProperty (CV_CAP_PROP_FRAME_WIDTH);
        i_height = (int)capture->getProperty (CV_CAP_PROP_FRAME_HEIGHT);
        i_offX =  (int)capture->getProperty (CV_CAP_PROP_GIGA_FRAME_OFFSET_X);
        i_offY =  (int)capture->getProperty (CV_CAP_PROP_GIGA_FRAME_OFFSET_Y);
        printf("-------------------------\n");
        print_properties (cap);
        printf("-------------------------\n");
    ...
        INT64 i = 0;
        cvNamedWindow("Frame",0);
        while(1) {
          if(i == 1000) {
            printf("------ Reset to original -------\n");
            (void)capture->setProperty (CV_CAP_PROP_FRAME_WIDTH, i_width);
            (void)cap->setProperty (CV_CAP_PROP_FRAME_HEIGHT, i_height);
            (void)capture->setProperty (CV_CAP_PROP_GIGA_FRAME_OFFSET_X, i_offX);
            (void)cap->setProperty (CV_CAP_PROP_GIGA_FRAME_OFFSET_Y, i_offY);
            print_properties (cap);
          }
          i++;
          IplImage* frame = cvQueryFrame (capture);
          if(frame)
            cvShowImage ("Frame",frame);
          if((cvWaitKey (3) == 27)) break;
        }
        cvDestroyWindow("Frame");
        cvReleaseCapture(&capture);
      }
      return 0;//a.exec();
    }
    



    Sincerely.
    Good luck!

    Also popular now: