一个 将一个无效参数传递给了将无效参数视为严重错误的函数 及写入位置时发生访问冲突的问题的解决

我的应用大体功能是这样的,使用opencv的接口,从摄像头实时读取color数据显示,并完全保存所有视频到硬盘,已经点击按钮之后将当前的数据帧保存为图片存储到硬盘。

 

第一个错误:                                     

第二个错误:

void FaceCapture::showColor(cv::Mat colorFrame)

{

   

    //colorframeMutex.lock();

    m_colorFrame = colorFrame;

    if (g_colorWriter.isOpened())

    {

        g_colorWriter << colorFrame;

    }

    //colorframeMutex.unlock();

 

    //cv::resize(colorFrame, frameForShow, dsize );

    int img_width = colorFrame.cols; // 在这行发生如上错误,上面两个错误都有可能发生。

    int img_height = colorFrame.rows;

    int channelnum = colorFrame.channels();

    if (NULL == g_prgbdatabuff)

    {

        g_prgbdatabuff = (uchar *)malloc(img_width * img_height * channelnum);

    }

 

    uchar* colorData = colorFrame.data;

    bool isColorImgTwoDark = true;

    int MaxValueCount = 0;

    for (int i = 0; i < img_width * img_height; i++)

    {

        int rgbaOffset = i * channelnum;

        g_prgbdatabuff[rgbaOffset] = colorData[rgbaOffset + 2];

        g_prgbdatabuff[rgbaOffset + 1] = colorData[rgbaOffset +1];

        g_prgbdatabuff[rgbaOffset + 2] = colorData[rgbaOffset];

 

        if ((255 == colorData[rgbaOffset + 2])

             && (255 == colorData[rgbaOffset + 1])

             && (255 == colorData[rgbaOffset]))

        {

             MaxValueCount++;

             isColorImgTwoDark = false;

        }

 

        if ((IMG_DARKNESS_THRESHOLD <= colorData[rgbaOffset + 2])

             || (IMG_DARKNESS_THRESHOLD <= colorData[rgbaOffset + 1])

             || (IMG_DARKNESS_THRESHOLD <= colorData[rgbaOffset]))

        {

             isColorImgTwoDark = false;

        }

    }

   

    QImage img(g_prgbdatabuff, img_width, img_height, QImage::Format_RGB888);

 

    QPixmap pixmap = QPixmap::fromImage(img);

    QPixmap scaredPixmap = pixmap.scaled(ui.label_color->width(), ui.label_color->height());

    ui.label_color->setPixmap(scaredPixmap);

 

    if (IMG_COLOR_OVER_EXPOSURE_PIXEL_COUNT <= MaxValueCount)

    {

        //ui.label_color_quality->setStyleSheet("color: rgb(255,0,0);");

        ui.label_color_quality->setText(QString::fromLocal8Bit("Color图像过度曝光"));

    }

    else if (true == isColorImgTwoDark)

    {

        //ui.label_color_quality->setStyleSheet("color: rgb(255,0,0);");

        ui.label_color_quality->setText(QString::fromLocal8Bit("Color图像过暗"));

    }

    else

    {

        //ui.label_color_quality->setStyleSheet("color: rgb(0,0,0);");

        ui.label_color_quality->setText(QString::fromLocal8Bit("Color图像正常"));

    }

 

    //free(data);

 

}

遇到这个问题,非常头大,网上的说法也乱七八糟。基本找不到一个可行的解决方案。而且这个问题也不是每一个数据帧都出现,不断的测试,突然什么时候就崩出来。

 

针对这个问题,第一反应是colorFrame 的Mat结构被破坏了。然后开始找各种关于Mat的信息。首先寻找判断判断Mat是否有效的两个函数:empty(如果Mat的data区域没有数据,或者尚未开辟空间,则返回false。),另一个是continuous(用来判断Mat中的数据是否是连续内存存的);加入如上两个判断之后发现虽然Mat比较大,1280*800的分辨率存储color数据,但是这两个判断基本上也都能通过,最后了解到像Mat结构确实比较特殊,Mat的赋值运算= 不会开辟新的空间,只会增加引用计数,于是找到可以使用clone或者copyto来进行深copy,多次尝试之后依然无法解决问题。另外了解到Mat 作为参数时,及时是直接传值其实也是传指针。搞过来搞过去,还是无法解决问题。

 

调用上面showColor函数的调用函数是如下的线程函数:

void ColorThread(VideoCapture cap)

{

    cv::Mat input_image;

    Rect faceRect;

    clock_t currentTime;

 

    bool isReadOk;

    while (g_running)

    {

        isReadOk = cap.read(input_image);

        if (false == isReadOk)

        {

             continue;

        }

 

        if (input_image.empty())

        {

             continue;

        }

                //这里拿到彩色图之后对图像进行人脸检测,检测成功后可以根据一定的条件设置ROI曝光

        detectFace(input_image, faceRect);       

             currentTime = clock();

 

             if (currentTime - LastSetRoiTime > (1 * CLOCKS_PER_SEC))

             {

                 if (faceRect.width > 50)

                 {

                     if (!CAEParamSetting::setAEROIArea(faceRect))

                     {

                         logUtil.error("WRITER BUFFER ERROR");

                     }

                 }

 

                 LastSetRoiTime = currentTime;

             }

       

 

        g_io_mutex.lock();

        g_w->showColor(input_image);

        g_io_mutex.unlock();

       

    }

}

根据上面的函数我又猜想是不是g_io_mutex使用lock不合适,showColor发生异常导致锁无法释放,于是改用lock_guard来包装g_io_mutex。这个方法也不凑效。

 

于是开始使用懒人定位法,一行一行注释掉看到底是哪一行发生问题。结果把g_w->showColor(input_image);注释掉后没发生问题。于是就盯着这个函数。然后进入这个函数,再一行一行的注释看是否能发生问题。最后发现,把如下保持视频的代码注释掉之后:

    if (g_colorWriter.isOpened())

    {

        g_colorWriter << colorFrame;

    }

这个问题很难出现。于是想到是不是得给主线程中操作g_colorWriter的地方加锁,g_colorWriter在应用中也会进行多次open及release。保证互斥访问。加锁之后果然问题解决。

 

应用中还有一个保存m_colorFrame图片到硬盘的imwrite操作,再刚才的调试过程中是注释掉的,现在放开之后,会再imwrite保存图片的地方也出现上述问题。于是在imwrite的地方加了同一把锁g_io_mutex。在这里加锁之后,问题果然解决。

 

到此,其实问题的原因已经比较清楚了,这是一个多线程访问共享数据,导致访问数据冲突出现的问题。

 

但是遇到另外一个问题。界面上的操作变得非常卡,于是想到应该是g_io_mutex锁保护的关键区域太多导致。将不必要的操作放到锁的外面,缩小关键区域之后,界面也不卡了。问题顺利解决。

 

 

  • 7
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值