繁体   English   中英

合并并提取BGR通道后,编译成功,但存在运行时错误:非法操作

[英]after merging and extracting the BGR channel, compilation is successful,but there is a run-time error: ILLEGAL OPERATION

我正在尝试从我已经拥有的3个不同的CV_8UC1图像创建1个CV_8UC3图像,即,我正在尝试将已经拥有的不同单通道图像分配到单个1多维图像中。 下面的代码可能可以完美地直接用于3通道图像,但是如果进行合并和提取,则会出现Runtime错误 非法操作

#include <opencv2/opencv.hpp>
#include <stdio.h>
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include<vector>
typedef cv::Vec3b Pixel;  //  correct


struct Operator {
    void operator ()(cv::Vec3b &pixel, const int * position) const 
    {    
            pixel[2]*=0.5; 
    }
}; 

int main(int argc, char** argv )
{
    cv::VideoCapture cap(0);
    if(!cap.isOpened())  
        return -1;
    cv::Mat frame1,frame2,for_each,cblue, cgreen, cred; 
    std::vector<cv::Mat> channels { cblue, cgreen, cred};
    for(;;)
    {
            cap >> frame1;    
            cvtColor(frame1, frame1, cv::COLOR_BGR2GRAY); 
            frame1.convertTo(frame2,CV_8U);

            frame2.copyTo(cblue);
            frame2.copyTo(cgreen);
            frame2.copyTo(cred);

            cv::merge(channels, for_each);

            double t1 = (double)cv::getTickCount();
            for_each.forEach<Pixel>(Operator());
            t1 = ((double)cv::getTickCount() - t1)/cv::getTickFrequency();
            std::cout<< "Parallel TEST time " << t1 << std::endl;

            cv::extractChannel (for_each, cblue, 0 );
            cv::imshow("cropped_BGR",frame1);
            cv::imshow("mod_BLUE",cblue);

           if (cv::waitKey(30) == 27) 
           {
                std::cout << "esc key is pressed by user" <<std::endl;
                 break; 
           }
    }
    return 0;

}

我不知道从哪里来这个错误,TIA会非常感谢您的帮助。

问题:

执行此操作时:

cv::Mat frame1,frame2,for_each,cblue, cgreen, cred; 
std::vector<cv::Mat> channels { cblue, cgreen, cred};

channels将具有cv::Mat cbluecgreencred的浅表副本。 这意味着它们都将具有相同的标头和指向相同位置的数据指针。

然后,您执行以下操作:

frame2.copyTo(cblue);
frame2.copyTo(cgreen);
frame2.copyTo(cred);

它将frame2的深层副本复制到每个cv :: Mat中。 copyTo的文档说:

m –目标矩阵。 如果在操作之前它的大小或类型不正确,则会对其进行重新分配。

这意味着,指向数据的指针将发生变化,但是不会更改为向量内的cv :: Mat,它们仍将指向nullptrcbluecgreencred将指向另一个位置。

我用以下代码进行了测试:

  cv::Mat frame(500, 500, CV_8UC3, cv::Scalar::all(111));
  cv::Mat frame1, frame2, cblue, cgreen, cred;
  std::vector<cv::Mat> channels{ cblue, cgreen, cred };
  // at this point all data members of mat will point to nullptr except frame
  cv::cvtColor(frame, frame, cv::COLOR_BGR2GRAY);
  frame.convertTo(frame2, CV_8U);

  frame2.copyTo(cblue);
  frame2.copyTo(cgreen);
  frame2.copyTo(cred);

  // at this point all point to another place except the ones inside the vector

可能的解决方案:

1)创建引用而不是副本:

  cv::Mat frame1, frame2;
  std::vector<cv::Mat> channels(3);
  cv::Mat& cblue = channels[0], &cgreen=channels[1], &cred=channels[2];

2)直接使用通道,而不使用其他变量

        frame2.copyTo(channels[0]);
        frame2.copyTo(channels[1]);
        frame2.copyTo(channels[2]);

3)在循环内创建向量

        frame2.copyTo(cblue);
        frame2.copyTo(cgreen);
        frame2.copyTo(cred);
        std::vector<cv::Mat> channels { cblue, cgreen, cred};
        cv::merge(channels, for_each);

4)您的代码等效于:

cvtColor(frame1, frame1, cv::COLOR_BGR2GRAY);
cvtColor(frame1, for_each, cv::COLOR_GRAY2BGR);

这将创建一个3通道的灰度值图像,基本上是每个通道中的灰度垫的副本...


5)还有一件事:

frame1.convertTo(frame2,CV_8U);

这不是必需的,因为它已经是CV_8U垫,因为上一条指令将其转换为CV_8U灰度,然后您甚至可以在其中创建向量而无需进行深拷贝(它将深拷贝到for_each)。

    std::vector<cv::Mat> channels { frame1, frame1, frame1};
    cv::merge(channels, for_each);

还有另一件事,与错误无关:

        cv::extractChannel (for_each, cblue, 0 );
        cv::imshow("cropped_BGR",frame1);
        cv::imshow("mod_BLUE",cblue);

将显示完全相同的图像:)或至少应显示。

确实,最好的答复之一。 非常感谢你 !!!

sol3 :效果很好

double t1 = (double)cv::getTickCount();
    std::vector<cv::Mat> channels { cblue, cgreen, cred};
    cv::merge(channels, for_each);
    for_each.forEach<Pixel>(Operator());
    cv::extractChannel (for_each, cblue, 2 );
t1 = ((double)cv::getTickCount() - t1)/cv::getTickFrequency();
std::cout<< "Parallel TEST time " << t1 << std::endl;

sol1 :但是它仍然给我

错误:“ class std :: vector”没有名为“ forEach”的成员。forEach(Operator()); ^ ~~~~~~ 16_vector_foreach_changedmaincode.cpp:54:31:错误:令牌通道之前的预期主表达式。forEach(Operator());

我的意图是

    frame2.copyTo(cblue);
    frame2.copyTo(cgreen);
    frame2.copyTo(cred);

double t1 = (double)cv::getTickCount();
    //std::vector<cv::Mat> channels { cblue, cgreen, cred};
    std::vector<cv::Mat> channels(3);
    cv::Mat& cblue = channels[0], &cgreen=channels[1], &cred=channels[2];
    //cv::merge(channels, for_each);
    channels.forEach<Pixel>(Operator());
    cv::extractChannel (channels, cblue, 2 );
t1 = ((double)cv::getTickCount() - t1)/cv::getTickFrequency();
std::cout<< "Parallel TEST time " << t1 << std::endl;

我还必须在这里使用合并运算符吗? @ api55

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM