Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/125.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 不必在OpenCV中复制Mat的最佳方法_C++_Opencv - Fatal编程技术网

C++ 不必在OpenCV中复制Mat的最佳方法

C++ 不必在OpenCV中复制Mat的最佳方法,c++,opencv,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)

我有一段代码,基本上是在两帧上进行“哑”背景减法

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\u foreground.copyTo(\u fgmask)
,则输出数组不会使用
img\u foreground
的结果进行更新,从而在调用时生成黑色图像


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

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

 _fgmask.create(img_input.size(), CV_8U);
我想这就是为什么你有这个问题。因为参数中的引用与此语句后面的引用不同。为什么不在调用函数之前先调用该行。

fix

  • 更改fgmask.create(img\u input.size(),CV\u 8U)
    \u fgmask.create(img\u input.size(),CV\u 8UC3)
    \u fgmask.create(img\u input.size(),img\u input.type())
为什么

  • 这是因为
    cv::absdiff(img_input_prev,img_input,img_front)每次在内部重新创建一个新数组。它确实会更新img_前台结构,但在分配之后,_fgmask中的内存地址数据无法更改,因为头是按值传递的。
    
    • 通过执行
      cv::Mat&img_foreground=\u fgmask.getMatRef(),似乎可以解决这个问题(但仍然会产生创建成本)
  • 这是因为CV_8U与CV_8UC3不同,因此Mat.hpp中的check@Mat::create()总是由于类型差异而分配新数组
意见

我想…也许用垫子代替

#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(修改后的原件)
\u fgmask
不是类的成员,只是参数。此外,添加这些参数并没有解决它:(我想这更多的是与OpenCV内部的一些模糊的事情有关,而不是由C++本身构造的。OpenCV的结构应该是按值传递的,它们都是轻量级结构(如CV:VEC)或动态存储器的头(如CV::MAT)。。所以原始原型是好的。@changelog在这种情况下,我认为参数已经被引用了。我再次检查了您的代码并更新了我的答案。您是否为调用方的
\u fgmask
的实际参数分配了内存?我不尝试向OpenCV提交补丁,而只是尝试使用加载的subt修改库使用与OpenCV相同的算法。当您调用
BackgroundSubtractor.operator()
时,该方法签名不起作用。我已经尝试了您的建议(通过将
传入.type()
)但是,当它将颜色转换为黑白时,它必须再次复制它,因为在另一面我得到了一个彩色图像。原因与在absdiff中发生新分配的原因完全相同。cvtcolor dst类型是8UC1,而给定类型是8UC3,因此opencv分配了新内存。而在absdiff的情况下,fgmask没有更新。您可以避免复制由
cv::cvtColor(img_前台,\u fgmask,cv_bgr2灰色);
编写的语句,但由于无论如何都会发生分配/复制,因此它的效率并不更高。我已经用一个完整的程序编辑了答案,该程序坚持原始结构,并尽可能重复使用(或者我可以弄清楚)我只是想回答为什么它不工作,而不是什么是最节省内存的方法(可能不需要关心,因为这不太可能是最大的瓶颈)。使用mat可以帮助您忘记这一点,因为它看起来更自动化。无论如何,更新的程序每周期的分配应该更少。@ZawLin,absDiff不适用于BGR mat图像,而只适用于灰度图像,对吗?这是因为,当我对彩色图像进行absDiff时,返回的都是空白图像,而如果我对其进行灰度化处理,则返回的都是空白图像首先是absDiff,我可以看到一个不同点,但是有很多信息丢失。@ZawLin,这是因为,在转换为灰度之前,你把absDiff放在第一位,而你不是唯一的一个。当我这样做的时候,即使我从相机的另一端挥手,如果给我一个空白图像,但是,如果我先将其灰度化,就不会发生这样的问题,因此我只想再确认一下(:
#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;
}