Refactored the PvAPI capture class to better facilitate dynamic property changes
authoraskforeric <askforeric@gmail.com>
Tue, 13 Nov 2012 21:10:22 +0000 (16:10 -0500)
committerAndrey Kamaev <andrey.kamaev@itseez.com>
Wed, 28 Nov 2012 07:28:16 +0000 (11:28 +0400)
- Added Gain control
- Changed default acquisition mode to grayscale
- Fixed a signed/unsigned compare issue
- Implemented frame resizing
- Implemented automatic buffer resizing on frame resize
- Corrected camera initialization so that it attempts to put the camera in Mono8
  but does not fail if this doesn't succeed.

modules/highgui/src/cap_pvapi.cpp

index fe94d8c..8d4a4a2 100644 (file)
@@ -95,6 +95,10 @@ protected:
     virtual void Sleep(unsigned int time);
 #endif
 
+    void stopCapture();
+    bool startCapture();
+    bool resizeCaptureFrame (int frameWidth, int frameHeight);
+
     typedef struct
     {
         unsigned long   UID;
@@ -113,6 +117,8 @@ protected:
 CvCaptureCAM_PvAPI::CvCaptureCAM_PvAPI()
 {
     monocrome=false;
+    frame = NULL;
+    grayframe = NULL;
     memset(&this->Camera, 0, sizeof(this->Camera));
 }
 
@@ -132,8 +138,7 @@ void CvCaptureCAM_PvAPI::Sleep(unsigned int time)
 void CvCaptureCAM_PvAPI::close()
 {
     // Stop the acquisition & free the camera
-    PvCommandRun(Camera.Handle, "AcquisitionStop");
-    PvCaptureEnd(Camera.Handle);
+    stopCapture();
     PvCameraClose(Camera.Handle);
     PvUnInitialize();
 }
@@ -162,7 +167,8 @@ bool CvCaptureCAM_PvAPI::open( int index )
 
     Camera.UID = cameraList[index].UniqueId;
 
-    if (!PvCameraInfo(Camera.UID,&camInfo) && !PvCameraIpSettingsGet(Camera.UID,&ipSettings)) {
+    if (!PvCameraInfo(Camera.UID,&camInfo) && !PvCameraIpSettingsGet(Camera.UID,&ipSettings))
+    {
         /*
         struct in_addr addr;
         addr.s_addr = ipSettings.CurrentIpAddress;
@@ -173,7 +179,8 @@ bool CvCaptureCAM_PvAPI::open( int index )
         printf("Current gateway:\t%s\n",inet_ntoa(addr));
         */
     }
-    else {
+    else
+    {
         fprintf(stderr,"ERROR: could not retrieve camera IP settings.\n");
         return false;
     }
@@ -181,73 +188,33 @@ bool CvCaptureCAM_PvAPI::open( int index )
 
     if (PvCameraOpen(Camera.UID, ePvAccessMaster, &(Camera.Handle))==ePvErrSuccess)
     {
-
-        //Set Pixel Format to BRG24 to follow conventions
-        /*Errcode = PvAttrEnumSet(Camera.Handle, "PixelFormat", "Bgr24");
-        if (Errcode != ePvErrSuccess)
-        {
-            fprintf(stderr, "PvAPI: couldn't set PixelFormat to Bgr24\n");
-            return NULL;
-        }
-        */
-        tPvUint32 frameWidth, frameHeight, frameSize;
+        tPvUint32 frameWidth, frameHeight;
         unsigned long maxSize;
-        char pixelFormat[256];
-        PvAttrUint32Get(Camera.Handle, "TotalBytesPerFrame", &frameSize);
+
+        // By Default, try to set the pixel format to Mono8.  This can be changed later
+        // via calls to setProperty. Some colour cameras (i.e. the Manta line) have a default
+        // image mode of Bayer8, which is currently unsupported, so Mono8 is a safe bet for
+        // startup.
+
+        monocrome = (PvAttrEnumSet(Camera.Handle, "PixelFormat", "Mono8") == ePvErrSuccess);
+
         PvAttrUint32Get(Camera.Handle, "Width", &frameWidth);
         PvAttrUint32Get(Camera.Handle, "Height", &frameHeight);
-        PvAttrEnumGet(Camera.Handle, "PixelFormat", pixelFormat,256,NULL);
+
+        // Determine the maximum packet size supported by the system (ethernet adapter)
+        // and then configure the camera to use this value.  If the system's NIC only supports
+        // an MTU of 1500 or lower, this will automatically configure an MTU of 1500.
+        // 8228 is the optimal size described by the API in order to enable jumbo frames
+
         maxSize = 8228;
         //PvAttrUint32Get(Camera.Handle,"PacketSize",&maxSize);
         if (PvCaptureAdjustPacketSize(Camera.Handle,maxSize)!=ePvErrSuccess)
             return false;
-        if (strcmp(pixelFormat, "Mono8")==0) {
-                grayframe = cvCreateImage(cvSize((int)frameWidth, (int)frameHeight), IPL_DEPTH_8U, 1);
-                grayframe->widthStep = (int)frameWidth;
-                frame = cvCreateImage(cvSize((int)frameWidth, (int)frameHeight), IPL_DEPTH_8U, 3);
-                frame->widthStep = (int)frameWidth*3;
-                Camera.Frame.ImageBufferSize = frameSize;
-                Camera.Frame.ImageBuffer = grayframe->imageData;
-        }
-        else if (strcmp(pixelFormat, "Mono16")==0) {
-                grayframe = cvCreateImage(cvSize((int)frameWidth, (int)frameHeight), IPL_DEPTH_16U, 1);
-                grayframe->widthStep = (int)frameWidth;
-                frame = cvCreateImage(cvSize((int)frameWidth, (int)frameHeight), IPL_DEPTH_16U, 3);
-                frame->widthStep = (int)frameWidth*3;
-                Camera.Frame.ImageBufferSize = frameSize;
-                Camera.Frame.ImageBuffer = grayframe->imageData;
-        }
-        else if (strcmp(pixelFormat, "Bgr24")==0) {
-                frame = cvCreateImage(cvSize((int)frameWidth, (int)frameHeight), IPL_DEPTH_8U, 3);
-                frame->widthStep = (int)frameWidth*3;
-                Camera.Frame.ImageBufferSize = frameSize;
-                Camera.Frame.ImageBuffer = frame->imageData;
-        }
-        else
-                return false;
-        // Start the camera
-        PvCaptureStart(Camera.Handle);
-
-        // Set the camera to capture continuously
-        if(PvAttrEnumSet(Camera.Handle, "AcquisitionMode", "Continuous")!= ePvErrSuccess)
-        {
-            fprintf(stderr,"Could not set Prosilica Acquisition Mode\n");
-            return false;
-        }
 
-        if(PvCommandRun(Camera.Handle, "AcquisitionStart")!= ePvErrSuccess)
-        {
-            fprintf(stderr,"Could not start Prosilica acquisition\n");
-            return false;
-        }
+        resizeCaptureFrame(frameWidth, frameHeight);
 
-        if(PvAttrEnumSet(Camera.Handle, "FrameStartTriggerMode", "Freerun")!= ePvErrSuccess)
-        {
-            fprintf(stderr,"Error setting Prosilica trigger to \"Freerun\"");
-            return false;
-        }
+        return startCapture();
 
-        return true;
     }
     fprintf(stderr,"Error cannot open camera\n");
     return false;
@@ -264,8 +231,10 @@ bool CvCaptureCAM_PvAPI::grabFrame()
 IplImage* CvCaptureCAM_PvAPI::retrieveFrame(int)
 {
 
-    if (PvCaptureWaitForFrameDone(Camera.Handle, &(Camera.Frame), 1000) == ePvErrSuccess) {
-        if (!monocrome) {
+    if (PvCaptureWaitForFrameDone(Camera.Handle, &(Camera.Frame), 1000) == ePvErrSuccess)
+    {
+        if (!monocrome)
+        {
             cvMerge(grayframe,grayframe,grayframe,NULL,frame);
             return frame;
         }
@@ -287,26 +256,31 @@ double CvCaptureCAM_PvAPI::getProperty( int property_id )
         PvAttrUint32Get(Camera.Handle, "Height", &nTemp);
         return (double)nTemp;
     case CV_CAP_PROP_EXPOSURE:
-    PvAttrUint32Get(Camera.Handle,"ExposureValue",&nTemp);
-    return (double)nTemp;
+        PvAttrUint32Get(Camera.Handle,"ExposureValue",&nTemp);
+        return (double)nTemp;
     case CV_CAP_PROP_FPS:
-    tPvFloat32 nfTemp;
+        tPvFloat32 nfTemp;
         PvAttrFloat32Get(Camera.Handle, "StatFrameRate", &nfTemp);
         return (double)nfTemp;
     case CV_CAP_PROP_PVAPI_MULTICASTIP:
-    char mEnable[2];
-    char mIp[11];
-    PvAttrEnumGet(Camera.Handle,"MulticastEnable",mEnable,sizeof(mEnable),NULL);
-    if (strcmp(mEnable, "Off") == 0) {
-        return -1;
-    }
-    else {
-        long int ip;
-        int a,b,c,d;
-        PvAttrStringGet(Camera.Handle, "MulticastIPAddress",mIp,sizeof(mIp),NULL);
-        sscanf(mIp, "%d.%d.%d.%d", &a, &b, &c, &d); ip = ((a*256 + b)*256 + c)*256 + d;
-        return (double)ip;
-    }
+        char mEnable[2];
+        char mIp[11];
+        PvAttrEnumGet(Camera.Handle,"MulticastEnable",mEnable,sizeof(mEnable),NULL);
+        if (strcmp(mEnable, "Off") == 0)
+        {
+            return -1;
+        }
+        else
+        {
+            long int ip;
+            int a,b,c,d;
+            PvAttrStringGet(Camera.Handle, "MulticastIPAddress",mIp,sizeof(mIp),NULL);
+            sscanf(mIp, "%d.%d.%d.%d", &a, &b, &c, &d); ip = ((a*256 + b)*256 + c)*256 + d;
+            return (double)ip;
+        }
+    case CV_CAP_PROP_GAIN:
+        PvAttrUint32Get(Camera.Handle, "GainValue", &nTemp);
+        return (double)nTemp;
     }
     return -1.0;
 }
@@ -315,19 +289,50 @@ bool CvCaptureCAM_PvAPI::setProperty( int property_id, double value )
 {
     switch ( property_id )
     {
-    /*  TODO: Camera works, but IplImage must be modified for the new size
     case CV_CAP_PROP_FRAME_WIDTH:
-        PvAttrUint32Set(Camera.Handle, "Width", (tPvUint32)value);
+    {
+        tPvUint32 currHeight;
+
+        PvAttrUint32Get(Camera.Handle, "Height", &currHeight);
+
+        stopCapture();
+        // Reallocate Frames
+        if (!resizeCaptureFrame(value, currHeight))
+        {
+            startCapture();
+            return false;
+        }
+
+        startCapture();
+
         break;
+    }
     case CV_CAP_PROP_FRAME_HEIGHT:
-        PvAttrUint32Set(Camera.Handle, "Heigth", (tPvUint32)value);
+    {
+        tPvUint32 currWidth;
+
+        PvAttrUint32Get(Camera.Handle, "Width", &currWidth);
+
+        stopCapture();
+
+        // Reallocate Frames
+        if (!resizeCaptureFrame(value, currWidth))
+        {
+            startCapture();
+            return false;
+        }
+
+        startCapture();
+
         break;
-    */
+    }
     case CV_CAP_PROP_MONOCROME:
-        if (value==1) {
+        if (value==1)
+        {
             char pixelFormat[256];
             PvAttrEnumGet(Camera.Handle, "PixelFormat", pixelFormat,256,NULL);
-            if ((strcmp(pixelFormat, "Mono8")==0) || strcmp(pixelFormat, "Mono16")==0) {
+            if ((strcmp(pixelFormat, "Mono8")==0) || strcmp(pixelFormat, "Mono16")==0)
+            {
                 monocrome=true;
             }
             else
@@ -338,31 +343,157 @@ bool CvCaptureCAM_PvAPI::setProperty( int property_id, double value )
         break;
     case CV_CAP_PROP_EXPOSURE:
         if ((PvAttrUint32Set(Camera.Handle,"ExposureValue",(tPvUint32)value)==ePvErrSuccess))
-        break;
-        else
-        return false;
-    case CV_CAP_PROP_PVAPI_MULTICASTIP:
-
-            if (value==-1) {
-        if ((PvAttrEnumSet(Camera.Handle,"MulticastEnable", "Off")==ePvErrSuccess))
             break;
         else
             return false;
+    case CV_CAP_PROP_PVAPI_MULTICASTIP:
+        if (value==-1)
+        {
+            if ((PvAttrEnumSet(Camera.Handle,"MulticastEnable", "Off")==ePvErrSuccess))
+                break;
+            else
+                return false;
         }
-        else {
-        std::string ip=cv::format("%d.%d.%d.%d", ((int)value>>24)&255, ((int)value>>16)&255, ((int)value>>8)&255, (int)value&255);
-        if ((PvAttrEnumSet(Camera.Handle,"MulticastEnable", "On")==ePvErrSuccess) &&
-        (PvAttrStringSet(Camera.Handle, "MulticastIPAddress", ip.c_str())==ePvErrSuccess))
-            break;
         else
+        {
+            std::string ip=cv::format("%d.%d.%d.%d", ((int)value>>24)&255, ((int)value>>16)&255, ((int)value>>8)&255, (int)value&255);
+            if ((PvAttrEnumSet(Camera.Handle,"MulticastEnable", "On")==ePvErrSuccess) &&
+                (PvAttrStringSet(Camera.Handle, "MulticastIPAddress", ip.c_str())==ePvErrSuccess))
+                break;
+            else
+                return false;
+        }
+    case CV_CAP_PROP_GAIN:
+        if (PvAttrUint32Set(Camera.Handle,"GainValue",(tPvUint32)value)!=ePvErrSuccess)
+        {
             return false;
         }
+        break;
     default:
         return false;
     }
     return true;
 }
 
+void CvCaptureCAM_PvAPI::stopCapture()
+{
+    PvCommandRun(Camera.Handle, "AcquisitionStop");
+    PvCaptureEnd(Camera.Handle);
+}
+
+bool CvCaptureCAM_PvAPI::startCapture()
+{
+    // Start the camera
+    PvCaptureStart(Camera.Handle);
+
+    // Set the camera to capture continuously
+    if(PvAttrEnumSet(Camera.Handle, "AcquisitionMode", "Continuous")!= ePvErrSuccess)
+    {
+        fprintf(stderr,"Could not set PvAPI Acquisition Mode\n");
+        return false;
+    }
+
+    if(PvCommandRun(Camera.Handle, "AcquisitionStart")!= ePvErrSuccess)
+    {
+        fprintf(stderr,"Could not start PvAPI acquisition\n");
+        return false;
+    }
+
+    if(PvAttrEnumSet(Camera.Handle, "FrameStartTriggerMode", "Freerun")!= ePvErrSuccess)
+    {
+        fprintf(stderr,"Error setting PvAPI trigger to \"Freerun\"");
+        return false;
+    }
+
+    return true;
+}
+
+bool CvCaptureCAM_PvAPI::resizeCaptureFrame (int frameWidth, int frameHeight)
+{
+    char pixelFormat[256];
+    tPvUint32 frameSize;
+    tPvUint32 sensorHeight;
+    tPvUint32 sensorWidth;
+
+
+    if (grayframe)
+    {
+        cvReleaseImage(&grayframe);
+        grayframe = NULL;
+    }
+
+    if (frame)
+    {
+        cvReleaseImage(&frame);
+        frame = NULL;
+    }
+
+    if (PvAttrUint32Get(Camera.Handle, "SensorWidth", &sensorWidth) != ePvErrSuccess)
+    {
+        return false;
+    }
+
+    if (PvAttrUint32Get(Camera.Handle, "SensorHeight", &sensorHeight) != ePvErrSuccess)
+    {
+        return false;
+    }
+
+    // Cap out of bounds widths to the max supported by the sensor
+    if ((frameWidth < 0) || ((tPvUint32)frameWidth > sensorWidth))
+    {
+        frameWidth = sensorWidth;
+    }
+
+    if ((frameHeight < 0) || ((tPvUint32)frameHeight > sensorHeight))
+    {
+        frameHeight = sensorHeight;
+    }
+
+
+    if (PvAttrUint32Set(Camera.Handle, "Height", frameHeight) != ePvErrSuccess)
+    {
+        return false;
+    }
+
+    if (PvAttrUint32Set(Camera.Handle, "Width", frameWidth) != ePvErrSuccess)
+    {
+        return false;
+    }
+
+    PvAttrEnumGet(Camera.Handle, "PixelFormat", pixelFormat,256,NULL);
+    PvAttrUint32Get(Camera.Handle, "TotalBytesPerFrame", &frameSize);
+
+
+    if (strcmp(pixelFormat, "Mono8")==0)
+    {
+        grayframe = cvCreateImage(cvSize((int)frameWidth, (int)frameHeight), IPL_DEPTH_8U, 1);
+        grayframe->widthStep = (int)frameWidth;
+        frame = cvCreateImage(cvSize((int)frameWidth, (int)frameHeight), IPL_DEPTH_8U, 3);
+        frame->widthStep = (int)frameWidth*3;
+        Camera.Frame.ImageBufferSize = frameSize;
+        Camera.Frame.ImageBuffer = grayframe->imageData;
+    }
+    else if (strcmp(pixelFormat, "Mono16")==0)
+    {
+        grayframe = cvCreateImage(cvSize((int)frameWidth, (int)frameHeight), IPL_DEPTH_16U, 1);
+        grayframe->widthStep = (int)frameWidth;
+        frame = cvCreateImage(cvSize((int)frameWidth, (int)frameHeight), IPL_DEPTH_16U, 3);
+        frame->widthStep = (int)frameWidth*3;
+        Camera.Frame.ImageBufferSize = frameSize;
+        Camera.Frame.ImageBuffer = grayframe->imageData;
+    }
+    else if (strcmp(pixelFormat, "Bgr24")==0)
+    {
+        frame = cvCreateImage(cvSize((int)frameWidth, (int)frameHeight), IPL_DEPTH_8U, 3);
+        frame->widthStep = (int)frameWidth*3;
+        Camera.Frame.ImageBufferSize = frameSize;
+        Camera.Frame.ImageBuffer = frame->imageData;
+    }
+    else
+        return false;
+
+    return true;
+}
 
 CvCapture* cvCreateCameraCapture_PvAPI( int index )
 {