вызов функции c по значению не работает

#c #function #opencv #byval

#c #функция #opencv #бывал

Вопрос:

У меня проблема с этим кодом:

Проблема в том, что когда я вижу оригинал изображения, он модифицируется «borrarFondo ()», но эта функция вызывается из «segmentarHoja», и здесь вводится img по значению, но img изменяется.

 void borrarFondo(Matamp; img){
   img = ~img;
   Mat background;
   medianBlur(img, background, 45);
   GaussianBlur(background, background, Size(203,203),101,101);
   img = img - background;
   img = ~img;
}

void segmentarHoja(Mat img, Matamp; imsheet){
   Mat imgbw;
   borrarFondo(img); //borrarFondo is called from here where img is a copy
   cvtColor(img, imgbw, CV_BGR2GRAY);
   threshold(imgbw, imgbw, 0, 255, CV_THRESH_BINARY | CV_THRESH_OTSU);
   Mat element = getStructuringElement(MORPH_ELLIPSE, Size(21,21));
   erode(imgbw, imgbw, element);
   vector<vector<Point> > contoursSheet; 
   findContours(imgbw, contoursSheet, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE);
   vector<Rect> boundSheet(contoursSheet.size());
   int largest_area=0;

   for( int i = 0; i< contoursSheet.size(); i   )
   {
        double a= contourArea( contoursSheet[i],false);
        if(a>largest_area){
           largest_area=a; 
           boundSheet[i] = boundingRect(contoursSheet[i]);
           imsheet=img(boundSheet[i]).clone(); 
        }
    }
    borrarFondo(imsheet);
  }

int main()
{
    Mat imsheet;
    image= imread("c:/imagen.jpg");
    segmentarHoja(image, imsheet);

    imshow("imsheet",imsheet);
    imshow("imagen",image); //original image by amending borrarFondo 
    waitKey(0);
}
  

Я не хочу менять исходное изображение

Комментарии:

1. void borrarFondo(Matamp; img) Вы не передавали по значению, вы передавали по ссылке. Именно поэтому вы изменяете img .

2. насколько я могу вспомнить, opencv Mat — это ссылка с подсчетом ссылок (т. Е. like std::shared_ptr , за исключением другого синтаксиса), где конструкция копирования или присваивание не копируются. хорошо, я только что проверил документы, что вы и должны были сделать. используйте clone метод для копирования.

3. @Cyber: нет, это не так, хотя это было бы естественным выводом, если ничего не знать Mat .

4. но эта функция вызывается из другой функции «segmentarHoja», где img передается по значению. В основном вызове segmentarHoja и в segmentarhoja вызов borrarFondo, img изменяется в segmentarHoja, но img в segmentarHoja передается по значению

Ответ №1:

opencv Mat — это подсчитанная ссылка (т. Е. Похожая std::shared_ptr , за исключением другого синтаксиса), где конструкция копирования или присваивание не копируются. используйте clone метод для копирования. прочитайте документацию, это всегда хорошая идея.

Комментарии:

1. тогда я не могу передать Mat по значению? следует ли передавать копию Mat with clone ?

2. Кстати, я также рассмотрел этот вопрос и ответ в соответствии с моим убеждением в том, что каждый обязан преподавать правильные вещи везде, где он сталкивается с неправильными представлениями. Но это становится утомительным, и мало кто хочет это делать. Так что просто будьте осторожны с советами, которые вы получаете на SO.

3. спасибо за все, я не очень понимаю по-английски, но я стараюсь узнать все об обработке изображений, и на испанском языке нет информации об этом xD, у меня есть школьный проект, который нужно сделать, я не подумал, что лучше что-то с opencv xD, теперь я должен это сделать

4. еще один вопрос, искусственный интеллект очень сложный? или через месяц я это понимаю?

5. @user3779874: Учтите, что некоторые из лучших умов на планете боролись с исследованиями и пытались создать искусственный интеллект с 1950-х годов, но пока безуспешно, и вы можете сделать вывод, что есть чему поучиться. Несмотря на это, простая арифметика говорит вам, что до получения необходимой мощности машины еще около 20-30 или более лет. Искусственный интеллект — это современное состояние, и это очень подвижная цель… НО , может быть, вы говорите о «движке искусственного интеллекта» игры. Я думаю, это нечто гораздо более практичное, о чем можно узнать. 🙂

Ответ №2:

если вы делаете что-то подобное:

 Mat a;
Mat b = a;
  

или как это:

 void func(Mat m) {...}
  

или :

 vector<Mat> vm; 
vm.push_back(m);
  

все это мелкая копия. заголовок Mat будет копией, указатели внутри тоже.

так, например, в 1-м примере b и a имеют одинаковый размер и элементы данных

это может объяснить, почему передача Mat по значению по-прежнему приводит к тому, что пиксели обрабатываются из «мелкой» копии.

чтобы избежать этого, вам придется вместо этого выполнить «глубокую» копию:

 Mat c = a.clone(); // c has its own pixels now.
  

и снова, если вы не хотите, чтобы вашим Mat можно было манипулировать, передайте его как a const Mat amp; будьте очень осторожны в том, как вы его используете, как показано ниже.

 #include <opencv2/opencv.hpp>

void foo( cv::Mat constamp; image )
{
    cv::Mat result = image;
    cv::ellipse(
        result,                     // img
        cv::Point( 300, 300 ),        // center
        cv::Size( 50, 50 ),         // axes (bounding box size)
        0.0,                        // angle
        0.0,                        // startAngle
        360.0,                      // endAngle
        cv::Scalar_<int>( 0, 0, 255 ),  // color
        6                           // thickness
        );
}

auto main() -> int
{
    auto window_name = "Display";
    cv::Mat lenna = cv::imread( "lenna.png" );
    foo( lenna );
    imshow( window_name, lenna );
    cv::waitKey( 0 );
}
  

Mat constamp; Ложь о изменчивости, и нос Ленны соответственно длинный, здесь отмечен большим жирным кругом, помещенным foo функцией выше:

введите описание изображения здесь

Комментарии:

1. хе-хе, ок. верно. 😉 спасибо, что указали, @Cheers и hth. — Alf