Search code examples
c++opencvbasler

OpenCV & C++: returned cv::Mat causes a Segmentation Fault


I'm writing a class that grabs frames from basler USB cameras using pylonAPI and converts them to openCV format. Here's the code of the grabbing method:

std::pair<cv::Mat, cv::Mat> GrabPair()
    {
        int key;
        Pylon::CImageFormatConverter fmtConv;
        Pylon::CPylonImage pylonImg1, pylonImg2;
        fmtConv.OutputPixelFormat = Pylon::PixelType_BGR8packed;
        Pylon::CPylonImage pylonImgLeft, pylonImgRight;

        cv::Mat outImageL, outImageR;
        Pylon::CGrabResultPtr pResultLeft, pResultRight;

        if(cams.IsGrabbing()){
            cams[leftCamIndex].RetrieveResult(1000, pResultLeft, Pylon::TimeoutHandling_ThrowException);    
            cams[rightCamIndex].RetrieveResult(1000, pResultRight, Pylon::TimeoutHandling_ThrowException);  

            if(pResultLeft->GrabSucceeded() && pResultRight->GrabSucceeded()){
                fmtConv.Convert(pylonImgLeft, pResultLeft);
                
                outImageL = cv::Mat(pResultLeft->GetHeight(), 
                    pResultLeft->GetWidth(), 
                    CV_8UC3,
                    (uint8_t*)pylonImgLeft.GetBuffer()
                );

                fmtConv.Convert(pylonImgRight, pResultRight);

                outImageR = cv::Mat(pResultRight->GetHeight(), 
                    pResultRight->GetWidth(), 
                    CV_8UC3,
                    (uint8_t*)pylonImgRight.GetBuffer()
                );

                /*cv::namedWindow("OpenCV out L");
                cv::namedWindow("OpenCV out R");

                cv::imshow("OpenCV out L", outImageL);
                cv::imshow("OpenCV out R", outImageR);
                key = cv::waitKey(20);*/
            }
        }

        return std::make_pair(outImageL, outImageR);                
    }

And this is the code fragment from main() where I try to acquire and show the grabbed frames

int key;
    BslrCap bc(40146142, 40146151); //the grabber object
    bc.PrintDevicesInfo();
    bc.Open();
    cv::Mat raw_left, raw_right;
    while(1)
    {        
        std::pair<cv::Mat, cv::Mat> images_pair = bc.GrabPair();
        cv::Mat raw_left = images_pair.first;
        cv::Mat raw_right = images_pair.second;

        if(!raw_right.empty() && !raw_left.empty()){            
            cv::namedWindow("OpenCV out L");
            cv::namedWindow("OpenCV out R");

            cv::imshow("OpenCV out L", raw_left);
            cv::imshow("OpenCV out R", raw_right);

            key = cv::waitKey(20);
        }
    }

But when I call cv::imshow I immediately receive SIGSEGV and my program crashes.

If I uncomment these lines in GrabPair() code:

                    pResultRight->GetWidth(), 
                    CV_8UC3,
                    (uint8_t*)pylonImgRight.GetBuffer()
                );

                /*cv::namedWindow("OpenCV out L");
                cv::namedWindow("OpenCV out R");

                cv::imshow("OpenCV out L", outImageL);
                cv::imshow("OpenCV out R", outImageR);
                key = cv::waitKey(20);*/

I can see two openCV windows on my screen with two captured frames. This means that both frames are captured without errors, and the problem is when I try to return std::pair from the method GrabPair() back to main()

Any ideas what I'm doing wrong?

Great thanks in advance!


Solution

  • the problem here is, that the Mat constructor using an external pointer is NOT refcounted. once you leave the GrabPair function, both Mat's are invalid (dangling pointer)

    you need to clone() them (deep copy of the data !) e.g. like:

        return std::make_pair(outImageL.clone(), outImageR.clone());