You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

OpenCV&C++技术问题:返回的cv::Mat引发段错误(SIGSEGV)

问题分析与解决方案

你的程序触发SIGSEGV的核心原因是悬空指针访问,具体细节和解决办法如下:

问题根源

在GrabPair()函数里,pylonImgLeft和pylonImgRight是局部栈变量。当函数执行完毕返回时,这两个Pylon::CPylonImage对象会被销毁,它们内部管理的图像缓冲区也会被自动释放。

而你创建cv::Mat的代码只是直接指向了这个缓冲区的指针:

outImageL = cv::Mat(pResultLeft->GetHeight(), pResultLeft->GetWidth(), CV_8UC3, (uint8_t*)pylonImgLeft.GetBuffer() );

这里的cv::Mat并没有复制像素数据,只是共享了pylonImgLeft的内存空间。当函数返回后,cv::Mat指向的内存已经被释放,在main函数中调用imshow访问这块无效内存,自然会触发段错误。

至于为什么GrabPair()内部注释掉的imshow能正常工作?因为此时pylonImgLeft/Right还在栈上存在,缓冲区内存处于有效状态,所以可以正常显示。

解决方案

有两种可靠的解决方式,你可以根据需求选择:

1. 让cv::Mat复制像素数据(简单直接)

修改GrabPair()中创建cv::Mat的代码,使用clone()方法让cv::Mat独立分配内存并复制数据,不再依赖Pylon::CPylonImage的缓冲区:

if(pResultLeft->GrabSucceeded() && pResultRight->GrabSucceeded()){
    fmtConv.Convert(pylonImgLeft, pResultLeft);
    // 使用clone()复制数据,让cv::Mat拥有独立内存
    outImageL = cv::Mat(pResultLeft->GetHeight(), pResultLeft->GetWidth(), CV_8UC3, (uint8_t*)pylonImgLeft.GetBuffer()).clone();
    fmtConv.Convert(pylonImgRight, pResultRight);
    outImageR = cv::Mat(pResultRight->GetHeight(), pResultRight->GetWidth(), CV_8UC3, (uint8_t*)pylonImgRight.GetBuffer()).clone();
}

这样返回的cv::Mat完全独立,函数返回后内存依然有效,main中的imshow就能正常工作。

2. 将Pylon::CPylonImage改为类成员变量(避免重复内存分配)

如果想避免每次抓取都复制数据的开销,可以把pylonImgLeft和pylonImgRight提升为BslrCap类的成员变量,让它们的生命周期和类对象一致:

// 在BslrCap类的头文件中添加成员变量
class BslrCap {
private:
    Pylon::CPylonImage m_pylonImgLeft, m_pylonImgRight;
    // 其他成员...
};

然后修改GrabPair()函数,去掉局部的pylonImgLeft/Right声明,直接使用类成员:

std::pair<cv::Mat, cv::Mat> GrabPair() {
    // ... 其他代码
    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(m_pylonImgLeft, pResultLeft);
            outImageL = cv::Mat(pResultLeft->GetHeight(), pResultLeft->GetWidth(), CV_8UC3, (uint8_t*)m_pylonImgLeft.GetBuffer() );
            fmtConv.Convert(m_pylonImgRight, pResultRight);
            outImageR = cv::Mat(pResultRight->GetHeight(), pResultRight->GetWidth(), CV_8UC3, (uint8_t*)m_pylonImgRight.GetBuffer() );
        }
    }
    return std::make_pair(outImageL, outImageR);
}

这样cv::Mat指向的缓冲区会随着BslrCap对象的存在而保持有效,不会出现悬空指针问题。

额外注意事项

  • 建议在GrabPair()函数开头确保outImageL和outImageR初始化为空矩阵,避免在抓取失败时返回未初始化的对象:
    cv::Mat outImageL, outImageR; // 默认构造即为空矩阵,也可以显式写cv::Mat()
    
  • 你的main函数中已经判断了raw_left和raw_right是否为空,这部分逻辑是正确的,可以保留。

内容的提问来源于stack exchange,提问作者Mikhail Grechukhin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.28 12:44:07