после слияния и извлечения канала BGR компиляция прошла успешно, но во время выполнения произошла ошибка: НЕЗАКОННАЯ ОПЕРАЦИЯ - PullRequest
0 голосов
/ 27 августа 2018

Я пытаюсь создать 1 изображение CV_8UC3 из 3 разных изображений CV_8UC1, которые у меня уже есть, то есть я пытаюсь выделить разные одноканальные изображения, которые у меня уже есть, в одно 1 многомерное изображение, Вероятно, приведенный ниже код работал безупречно напрямую с 3-канальным изображением, но при слиянии и извлечении он вызывает ошибку времени выполнения . НЕЗАКОННАЯ ЭКСПЛУАТАЦИЯ

#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.

Ответы [ 2 ]

0 голосов
/ 29 августа 2018

Действительно, один из лучших ответов.Большое спасибо !!!

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 : однако он все еще дает мне

ошибка: в классе std :: vector нет члена с именем forEach channel.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

0 голосов
/ 27 августа 2018

Проблема:

Когда вы сделаете это:

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

channels будет иметь мелкую копию cv::Mat cblue, cgreen и cred,Это означает, что у них обоих будут одинаковые заголовки с указателем данных, который будет указывать на одно и то же место.

Затем вы делаете:

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

, который делает глубокую копию frame2 для каждого из cv :: Mat.Документация copyTo гласит:

m - Матрица назначения.Если он не имеет правильного размера или типа перед операцией, он перераспределяется.

Это означает, что указатель на данные изменится, однако он не изменится на cv :: Mat внутривектор, они все равно будут указывать на nullptr, но cblue, cgreen и cred будут указывать на другое место.

Я проверил это с помощью этого кода:

  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, а затем вы даже можете создать вектор thБез глубокого копирования (глубокое копирование в 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);

будет отображать точното же самое изображение :) или должно по крайней мере.

...