Как говорил Генрих VIII очередной жене, — «Я вас долго не задержу...»
Пост — небольшое расширение предыдущей статьи «Qt + OpenCV. Runtime и Widget для CvCapture (устройства видеозахвата).»
Если вас, уважаемый читатель, угораздило приобрести видеокамеру, поддержка которой не обеспечена библиотекой OpenCV, а методы работы оной с изображениями ой как нужны, не следует расстраиваться.
Сперва изучим, что нам преподнесли, или что сами, несведующие, купили.
Итак, я стал «счастливчиком» по плюсикам этого списка, заполучив камеру Smartek Giganetix GC1921M
Методы SDK работают, но как-то так… Код частично закрыт.Уровень программиста стал понятен из фрагмента кода
Если у вас возник вопрос, — «А что тут такого?», — я не смогу отправить вас на машине времени в советский вуз, где за это с вас снимут балл на экзамене. :)
Да, и ладно. Нам-то нужно, всего лишь, подключиться, принять поток и отключиться. Благо, примеры — на месте.
Спасибо разработчикам библиотеки OpenCV за код, распрпостраняемый под BSD лицензией.
Речь идёт о версии 2.4.2.
Изучим часть исходников в каталоге modules/highgui/src. Как видим, всё несложно. Можно, просто скопировав похожий модуль, например cap_pvapi.cpp, под собственное устройство cap_giganetix.cpp сделать надлежащие правки, внести изменения (новый метод и элементы перечислений enum) в код precomp.hpp и соответствующие файлы директив для cmake и запустить сборку.
Это — первый метод. Основной минус — всё меняется от версии к версии, и пересборки новых релизов неизбежны.
Существует и более стабильный, если так можно назвать, вариант — реализация собственного CvCaptute для нового устройства, совместимого со структурой из OpenCV. Плюс в том, что разработчик помещаетвсю эту байду все свои зазработки в отдельную библиотеку, которая по требованиям зависимостей подгрузит и SDK на новое устройство, и OpenCV.
Минус, как всегда, в наличии «кота в мешке» — реализации на стороне разработчиков OpenCV скрытой структуры CvCapture.
Рассмотрим последний вариант.
Вначалебыло слово обеспечим совместимость с макросами, значениями перечислений исходных и заголовочных файлов OpenCV.
Участок
А так, мы просто добавили некоторые свойства для нашего устройства.
Создадим методы-оболочки для функций SDK нашей камеры. Это позволит минимизировать изменения в нашем коде при возможной правке разработчиками SDK собственного. Думаю, это — хороший стиль.
Обратите внимание на то, что объявление
Пишем реализацию класса и метода
Архив проекта заберите по ссылке
Приведу лишь код метода
Показано, как использовать макросы согласно стилю программирования от OpenCV.
Под привилегиями cуперпользователя в каталоге /usr/lib размещаем ссылки на новую библиотеку и… приступаем к тестированию.
С уважением.
Успехов!
Пост — небольшое расширение предыдущей статьи «Qt + OpenCV. Runtime и Widget для CvCapture (устройства видеозахвата).»
Если вас, уважаемый читатель, угораздило приобрести видеокамеру, поддержка которой не обеспечена библиотекой OpenCV, а методы работы оной с изображениями ой как нужны, не следует расстраиваться.
Сперва изучим, что нам преподнесли, или что сами, несведующие, купили.
- Интерфейс GigE поддерживается SDK, лежащей в свободном доступе или поставленной совместно с товаром. Первый плюс!
- Документация более-менее осмыслена. Снова повезло!
- Примеры есть! Надо же… Плюс!
Итак, я стал «счастливчиком» по плюсикам этого списка, заполучив камеру Smartek Giganetix GC1921M
Методы SDK работают, но как-то так… Код частично закрыт.
... if (m_selectedDevice->IsConnected()){ m_disconnectAct->setEnabled(true); m_fwUpdateAct->setEnabled(true); } ...
Если у вас возник вопрос, — «А что тут такого?», — я не смогу отправить вас на машине времени в советский вуз, где за это с вас снимут балл на экзамене. :)
Да, и ладно. Нам-то нужно, всего лишь, подключиться, принять поток и отключиться. Благо, примеры — на месте.
Варианты реализаций собственного устройства видеозахвата.
Спасибо разработчикам библиотеки OpenCV за код, распрпостраняемый под BSD лицензией.
Речь идёт о версии 2.4.2.
Изучим часть исходников в каталоге modules/highgui/src. Как видим, всё несложно. Можно, просто скопировав похожий модуль, например cap_pvapi.cpp, под собственное устройство cap_giganetix.cpp сделать надлежащие правки, внести изменения (новый метод и элементы перечислений enum) в код precomp.hpp и соответствующие файлы директив для cmake и запустить сборку.
Это — первый метод. Основной минус — всё меняется от версии к версии, и пересборки новых релизов неизбежны.
Существует и более стабильный, если так можно назвать, вариант — реализация собственного CvCaptute для нового устройства, совместимого со структурой из OpenCV. Плюс в том, что разработчик помещает
Минус, как всегда, в наличии «кота в мешке» — реализации на стороне разработчиков OpenCV скрытой структуры CvCapture.
Рассмотрим последний вариант.
Внешняя библиотека устройства видеозахвата типа CvCapture.
Вначале
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
Участок
приведёт код к правилам разработки модулей OpenCV. В чужой монастырь со своим уставом не лезь!//precomp.hpp double #define __BEGIN__ __CV_BEGIN__ #define __END__ __CV_END__ #define EXIT __CV_EXIT__
А так, мы просто добавили некоторые свойства для нашего устройства.
Создадим методы-оболочки для функций SDK нашей камеры. Это позволит минимизировать изменения в нашем коде при возможной правке разработчиками SDK собственного. Думаю, это — хороший стиль.
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
И, собственно, само наше устройство (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
Обратите внимание на то, что объявление
struct CvCapture взято из исходных кодов OpenCV (каталог modules/highgui/src, файл precomp.hpp). Вот оно, узкое место библиотеки!Пишем реализацию класса и метода
cvCreateCameraCapture_Giganetix.Архив проекта заберите по ссылке
Приведу лишь код метода
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; } ...
Показано, как использовать макросы согласно стилю программирования от OpenCV.
Файл проекта оформляем как динамически подключаемую библиотеку c обращением к SDK и 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
Под привилегиями cуперпользователя в каталоге /usr/lib размещаем ссылки на новую библиотеку и… приступаем к тестированию.
Тестовый пример.
Код
#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(); }
С уважением.
Успехов!
