簡體   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