📜 ⬆️ ⬇️

Qt + OpenCV. New device GigE interface access to network cameras as CvCapture

In the words of Henry VIII to his next wife, - "I will not keep you for a long time ..."
Post - 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 how to work with images oh, as needed, you should not be upset.
First, we will examine what they have presented to us, or what they themselves, the ignorant, bought.
  1. The GigE interface is supported by an SDK that is freely available or shared with the product. The first plus!
  2. Documentation is more or less meaningful. Lucky again!
  3. There are examples! Wow ... Plus!

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

If you have a question, - “And what's wrong with that?” - I can’t send you to a Soviet high school in a time machine, where you will be deducted from an exam for this. :)
Yeah, fine. We just need to connect, accept the stream and disconnect. Fortunately, examples are in place.

Variants of the implementation of its own video capture device.


Thanks to the developers of the OpenCV library for the code distributed under the BSD license.
This is version 2.4.2.
Let's study a part of source codes in the modules / highgui / src directory. As you can see, everything is easy. You can simply copy a similar module, for example cap_pvapi.cpp, make proper edits for your own device cap_giganetix.cpp, make changes (new method and enum enum 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 rebuilding of new releases is inevitable.
There is also a more stable, if you can call it that, option — an implementation of your own CvCaptute for a new device compatible with the structure from OpenCV. The plus is that the developer places all this canoe with all his backlogs in a separate library, which, according to the dependency requirements, will load the SDK to the new device, and OpenCV.
The minus, as always, is in the presence of the “cat in the bag” - the implementation on the side of the OpenCV developers of the hidden structure CvCapture.
Consider the last option.

External library of video capture device type CvCapture.

Initially , the word was to ensure compatibility with macros, enumeration values ​​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 . In a strange monastery with its charter do not go!
And so, we just added some properties for our device.
Let's create wrapper methods for the SDK functions of our camera. This will minimize the changes in our code when the SDK developers can edit their own. 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 <GigEVisionSDK.h> 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, actually, our device itself (cap_giganetix.h)
 #ifndef CAP_GIGANENIX_H #define CAP_GIGANENIX_H #include <opencv2/highgui/highgui_c.h> #include "GigEVisionSDK.h" #include "../../common/macros.hpp" #include <QObject> #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 


Note that the struct CvCapture is taken from OpenCV source codes ( modules / highgui / src directory, precomp.hpp file). Here it is, the bottleneck of the library!

We write the implementation of the class and the cvCreateCameraCapture_Giganetix method.
Archive of the project take on the link
I will cite only the open method code:
 ... /*----------------------------------------------------------------------------*/ 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; } ... 

Shows how to use macros according to the OpenCV programming style.

The project file is designed as a dynamic link 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 the superuser privileges in the / usr / lib directory, we place links to the new library and ... proceed to testing.

Test case


Code
 #include <QtGui/QApplication> #include "../../common/macros.hpp" #include <stdio.h> #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.
Successes!

Source: https://habr.com/ru/post/148850/


All Articles