最好不要在OpenCV中复制Mat的方法

时间:2013-10-02 14:57:36

标签: c++ opencv

我有这个代码,基本上在两个帧上进行“哑”背景减法。

void FrameDifferenceBGS::operator()(cv::InputArray _image, cv::OutputArray _fgmask, double learningRate)
{
  cv::Mat img_input = _image.getMat();

  if(img_input.empty())
    return;

  _fgmask.create(img_input.size(), CV_8U);
  cv::Mat img_foreground = _fgmask.getMat();

  if(img_input_prev.empty())
  {
    img_input.copyTo(img_input_prev);
    return;
  }

  cv::absdiff(img_input_prev, img_input, img_foreground);

  if(img_foreground.channels() == 3)
    cv::cvtColor(img_foreground, img_foreground, CV_BGR2GRAY);

  if(enableThreshold)
    cv::threshold(img_foreground, img_foreground, threshold, 255, cv::THRESH_BINARY);

  if(showOutput)
    cv::imshow("Frame Difference", img_foreground);

  img_input.copyTo(img_input_prev);
  img_foreground.copyTo(_fgmask);
  firstTime = false;
}

如果我最后没有添加img_foreground.copyTo(_fgmask),则输出数组不会使用img_foreground的结果进行更新,在调用此结果时会产生黑色图像。

我做错了什么/应该在这里做什么?

2 个答案:

答案 0 :(得分:1)

我再次审核了您的代码。看起来您正在为_fgmask创建新对象。

 _fgmask.create(img_input.size(), CV_8U);

我认为这就是你遇到问题的原因。因为这个参数中的引用不同于此语句之后的引用。在调用函数之前,为什么不调用该行。

答案 1 :(得分:1)

修复

  • _fgmask.create(img_input.size(), CV_8U);更改为_fgmask.create(img_input.size(), CV_8UC3);_fgmask.create(img_input.size(), img_input.type());

为什么

  • 这是因为cv::absdiff(img_input_prev, img_input, img_foreground);每次都在内部重新创建一个新数组。并且它确实更新了img_foreground结构,但是在分配之后,_fgmask中的内存地址数据无法更改,因为标头是按值传递的。
    • 你可以通过cv::Mat& img_foreground = _fgmask.getMatRef();
    • 来解决这个问题(但仍会产生创作成本)
  • 这是因为CV_8U与CV_8UC3不同,因此mat.hpp中的check @ Mat :: create()因类型不同而总是分配一个新数组

看来

我认为......也许使用Mat?

#include "opencv2/opencv.hpp"
using namespace cv;

class FrameDifferenceBGS
{
public:
    Mat prev;
    Mat diff;
    bool enableThreshold;
    bool showOutput;
    bool firstTime;
    uchar threshold;
    FrameDifferenceBGS():firstTime(false),enableThreshold(false),showOutput(false),threshold(0)
    {

    }
    void FrameDifferenceBGS::operator()(cv::Mat& _in, cv::Mat &_fg, double _lr)
    {
        if(_in.empty())
            return;

        if(prev.empty())
        {
            prev=_in.clone();
            _fg=cv::Mat::zeros(_in.size(),CV_8UC1);
            return;
        }

        cv::absdiff(prev, _in, diff);

        if(diff.channels() == 3)
            cv::cvtColor(diff, _fg, CV_BGR2GRAY);
        else
            _fg=diff;

        if(enableThreshold)
            cv::threshold(_fg, _fg, threshold, 255, cv::THRESH_BINARY);

        if(showOutput)
            cv::imshow("Frame Difference", _fg);

        prev=_in.clone();
        firstTime = false;
    }
};

int main()
{
    VideoCapture cap(0);
    FrameDifferenceBGS bgs;
    Mat frame,fg;
    for(;;)
    {
        cap >> frame; 
        bgs(frame,fg,0);

        imshow("frame", frame);
        imshow("fg", fg);
        if(waitKey(1) ==27) exit(0);
    }
    return 0;
}    

编辑2(修改原文)

#include "opencv2/opencv.hpp"

class FrameDifferenceBGS
{
public:
    cv::Mat img_input_prev;
    cv::Mat diff;

    cv::Mat img_foreground;//put this in class in stead of inside the function
    bool enableThreshold;
    bool showOutput;
    bool firstTime;
    uchar threshold;
    FrameDifferenceBGS():firstTime(false),enableThreshold(false),showOutput(false),threshold(0)
    {

    }
    void FrameDifferenceBGS::operator()(cv::InputArray _image, cv::OutputArray _fgmask, double learningRate)
    {
        cv::Mat img_input = _image.getMat();

        if(img_input.empty())
            return;
        if(_fgmask.empty())
            _fgmask.create(img_input.size(), CV_8UC1);
        if(img_input_prev.empty())
        {
            img_input.copyTo(img_input_prev);
            return;
        }

        cv::absdiff(img_input_prev, img_input, img_foreground);

        if(img_foreground.channels() == 3)
            cv::cvtColor(img_foreground, _fgmask, CV_BGR2GRAY);

        if(enableThreshold)
            cv::threshold(img_foreground, img_foreground, threshold, 255, cv::THRESH_BINARY);

        if(showOutput)
            cv::imshow("Frame Difference", img_foreground);

        img_input.copyTo(img_input_prev);
        //img_foreground.copyTo(_fgmask);
        firstTime = false;
    }
};

int main()
{
    cv::VideoCapture cap(0);
    FrameDifferenceBGS bgs;
    cv::Mat frame,fg;
    for(;;)
    {
        cap >> frame; 
        bgs(frame,fg,0);

        cv::imshow("frame", frame);
        cv::imshow("fg", fg);
        if(cv::waitKey(1) ==27) exit(0);
    }
    return 0;
}