На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
[!] Как относитесь к модерированию на этом форуме? Выскажите свое мнение здесь
Модераторы: Qraizer
  
> Медиана, OpenCV, массивы-векторы и пр.... , Споткнулся на ровном месте...
    Всем доброго времени суток!

    Заставили переводить код с Питона (в нем задействована OpenCV с auto_canny). Нашел на GitHub реализацию нужной функции на C++. Что-то не понимаю я почему у меня необработанное исключение выскакивает при копировании входного Mat в вектор при определении медианы. Или туплю конкретно, или подскажите где ошибся.... Очень давно на VC++ не писал... Может, поменялось что?

    VS 2015 комьюнити
    Измененный немного код ниже
    ExpandedWrap disabled
      double medianMat(cv::Mat Input)
      {
          Input = Input.reshape(0, 1);// spread Input Mat to single row
          std::vector<double> vecFromMat;
          Input.copyTo(vecFromMat); // Copy Input Mat to vector vecFromMat <-- НА ЭТОЙ СТРОКЕ ИСКЛЮЧЕНИЕ
          std::nth_element(vecFromMat.begin(), vecFromMat.begin() + vecFromMat.size() / 2, vecFromMat.end());
          return vecFromMat[vecFromMat.size() / 2];
      }
       
      cv::Mat auto_canny(cv::Mat &image, cv::Mat &output, float sigma = 0.33)
      {
          int low_H = 30, low_S = 150, low_V = 50;
          int high_H = 255, high_S = 255, high_V = 180;
       
          //convert to grey colour space
          cv::cvtColor(image, output, cv::COLOR_BGR2HSV);
          cv::Mat msk, res;
      //  cv::Mat l =
          inRange(output, cv::Scalar(low_H, low_S, low_V), cv::Scalar(high_H, high_S, high_V), msk);
          bitwise_and(output, output, output, msk);
       
          //apply small amount of Gaussian blurring
          //cv::GaussianBlur(output, output, cv::Size(3, 3), 0, 0);
          //get the median value of the matrix
          double v = medianMat(output);
          //generate the thresholds
          //int lower = (int)std::max(0.0, (1, 0 - sigma)*v); // было так
          //int upper = (int)std::min(255.0, (1, 0 + sigma)*v); // было так
          int lower = (int)std::max(0.0, 4.0*(1, 0 - sigma)*v); // определение нижней границы фильтра; коэффициент 4 подобран вручную после сравнения ярких и тёмных полос
          int upper = (int)std::min(255.0, 3.5*(1, 0 + sigma)*v); // определение верхней границы фильтра; коэффициент 3.5 подобран вручную после сравнения ярких и тёмных полос
          //apply canny operator
          cv::Canny(output, output, lower, upper, 3);
          return output;
      }

    Мелочь какая-то, ведь, скорее всего... Подскажите, ребят....
      Цитата =SAPSAN= @
      Input.copyTo(vecFromMat); // Copy Input Mat to vector vecFromMat <-- НА ЭТОЙ СТРОКЕ ИСКЛЮЧЕНИЕ

      Какое исключение? Может быть оно ожидает не пустой вектор, а размером с оригинал?
      Попробуй вектору сделать resize, перед тем как передавать его в copyTo.
      Плюс ко всему, параметр передается по значению, будет создана копия:
      Цитата =SAPSAN= @
      double medianMat(cv::Mat Input)

      Ты точно так хотел сделать? Может быть лучше по ссылке передать?
      ExpandedWrap disabled
        double medianMat(cv::Mat& Input)

      ?
        Исключение возникает "Возникло необработанное исключение по адресу 0x00007FFC8D049129 в Edges.exe: исключение Microsoft C++: cv::Exception по адресу памяти 0x00000080423DE150."
        Причем без разницы каким способом передача происходит - сейчас попробовал по ссылке - выскочило то,, что указал выше
          Лучше наверное привести весь код, включая то, чем инициализируется "cv::Mat &image".
            Цитата JoeUser @


            А он (код) простенький
            ExpandedWrap disabled
              int main(int, char **)
              {
                  VideoCapture cap(filevideo);
                  if (!cap.isOpened())  // check if we succeeded
                  {
                      cout << "Cannot open the video file" << endl;
                      cin.get(); //wait for any key press
                      return -1;
                  }
                  Mat edges;
                  namedWindow("edges", WINDOW_AUTOSIZE);
                  
               
                  for (;;)
                  {
                  Mat frame;
                  cap >> frame; // get a new frame from camera
                  double timestamp = cap.get(CAP_PROP_POS_MSEC);
                  auto_canny(frame, edges, 0.5);
                  
                  imshow("edges", edges);
                  if (waitKey(33) == 27) break; // выходим по ESC вне зависимости от раскладки
                  }
                  return 0;
              }

            Это без всего лишнего код
              Я так понимаю, что вместо всех этих захватов можно скормить просто одно изображение для теста?
              И если "да", какой формат изображения должен быть?

              Добавлено
              И попутно вопрос: сразу же на первой итерации валится прога?
                Изображение - обычный битмап
                валится на первой же итерации
                если не вызывать auto_canny, а сделать так
                ExpandedWrap disabled
                  cvtColor(frame, edges, COLOR_BGR2GRAY);
                  GaussianBlur(edges, edges, Size(7, 7), 1.5, 1.5);
                  Canny(edges, edges, 0, 30, 3);

                то все работает
                Валится все только на копировании в вектор для нахождения медианы
                  Цитата =SAPSAN= @
                  Валится все только на копировании в вектор для нахождения медианы

                  Так а что функция принимает, куда ты свой вектор передаешь? Может она ждет массив с выделенной памятью? Ты туда передаешь по сути пустой вектор, с 0 размером.
                  И текст исключения хорошо бы почитать. Перехвати его с помощью catch(cv::Exception& error) что оно там пишет то хоть?
                    У меня что-то в голове плохо укладывается...
                    Смотрите, метод Mat::copyTo() ждет матрицу на вход, а автор кода ему подсовывает вектор... Это как?

                    Добавлено
                    Код не мой - это с гитхаба.... Опередили меня
                      Цитата =SAPSAN= @
                      Смотрите, метод Mat::copyTo() ждет матрицу на вход, а автор кода ему подсовывает вектор... Это как?


                      Там они с перегрузками, а так если валится - копирует в невалидную память, она может быть не выделена скорее всего или недостаточно ее. Там же исходники библиотеки есть, попробуй по ним пройтись.
                        Цитата Wound @
                        Так а что функция принимает, куда ты свой вектор передаешь? Может она ждет массив с выделенной памятью? Ты туда передаешь по сути пустой вектор, с 0 размером.

                        Цитата
                        void cv::Mat::copyTo(OutputArray m) const

                        Copies the matrix to another one.

                        The method copies the matrix data to another matrix. Before copying the data, the method invokes :
                        m.create(this->size(), this->type());

                        so that the destination matrix is reallocated if needed. While m.copyTo(m); works flawlessly, the function does not handle the case of a partial overlap between the source and the destination matrices.

                        When the operation mask is specified, if the Mat::create call shown above reallocates the matrix, the newly allocated matrix is initialized with all zeros before copying the data.

                        Parameters
                        m Destination matrix. If it does not have a proper size or type before the operation, it is reallocated.
                          Пишет msg = "OpenCV(4.1.1) C:\\build\\master_winpack-build-win64-vc14\\opencv\\modules\\core\\src\\copy.cpp:254: error: (-215:Assertion failed) channels() == CV_MAT_CN(dtype) in function 'cv::Mat::copyTo'\n"
                          Как-будто все как я и говорил... Или не?
                            Цитата Wound @
                            Перехвати его с помощью catch(cv::Exception& error) что оно там пишет то хоть?

                            Во-во ... из доки как раз:
                            ExpandedWrap disabled
                              try
                              {
                                  ... // call OpenCV
                              }
                              catch (const cv::Exception& e)
                              {
                                  const char* err_msg = e.what();
                                  std::cout << "exception caught: " << err_msg << std::endl;
                              }
                              Цитата JoeUser @
                              Цитата Wound @
                              Перехвати его с помощью catch(cv::Exception& error) что оно там пишет то хоть?

                              Во-во ... из доки как раз:
                              ExpandedWrap disabled
                                try
                                {
                                    ... // call OpenCV
                                }
                                catch (const cv::Exception& e)
                                {
                                    const char* err_msg = e.what();
                                    std::cout << "exception caught: " << err_msg << std::endl;
                                }

                              еще раз - 0x000001bae45fa070 "OpenCV(4.1.1) C:\\build\\master_winpack-build-win64-vc14\\opencv\\modules\\core\\src\\copy.cpp:254: error: (-215:Assertion failed) channels() == CV_MAT_CN(dtype) in function 'cv::Mat::copyTo'
                                =SAPSAN=, ну не зря я про формат изображения вроде спрашивал. Похоже на то.
                                Вот что народ про твою ошибку пишет:
                                Цитата
                                The channels of your two images do not match. So you are trying to copy a bgr image to a grayscale image or something like that. Check the types of your images.


                                Добавлено
                                Я бы посоветовал сперва добиться результата без ошибки на каком-то простом изображении.
                                Ну а потом бы исследовал что там камера захвата выдает. Ну и корректировал бы по ходу.
                                  Смотрите, где косяк обнаружился

                                  ExpandedWrap disabled
                                    cv::cvtColor(image, output, cv::COLOR_BGR2GRAY); // это на гитхабе и все работает


                                  а мне надо


                                  ExpandedWrap disabled
                                    cv::cvtColor(image, output, cv::COLOR_BGR2HSV); // это не работает
                                    Это уже другая песня :)
                                      Так всегда. Одно решаем - тут же другое появляется. Есть идеи как получить желаемое? Мне от openCV только это и нужно.... Остальное с питона переводится на раз...
                                      Сообщение отредактировано: =SAPSAN= -
                                        Цитата =SAPSAN= @
                                        Есть идеи как получить желаемое?

                                        Тут идей нет - с либой совсем незнаком.
                                          Короче, отвечаю сам себе и всем остальным....

                                          Медиану при входной матрице в формате HSV можно было посчитать так:
                                          ExpandedWrap disabled
                                            double medianMat(cv::Mat Input)
                                            {
                                                std::vector<cv::Mat> channels;
                                                cv::split(Input, channels);
                                                Input = channels[0];
                                                Input = Input.reshape(0, 1);// spread Input Mat to single row
                                                std::vector<double> vecFromMat;
                                                Input.copyTo(vecFromMat); // Copy Input Mat to vector vecFromMat
                                                std::nth_element(vecFromMat.begin(), vecFromMat.begin() + vecFromMat.size() / 2, vecFromMat.end());
                                                return vecFromMat[vecFromMat.size() / 2];
                                            }

                                          НО!..
                                          ExpandedWrap disabled
                                            cv::Canny(output, output, lower, upper, 3);
                                            // или
                                            cv::Canny(output, output, lower, upper);

                                          не хочет работать СОВСЕМ... Плюнул я на это дело и решил пойти другим путем. Конвертацию в полутона оставил как есть, а на выходе из auto_canny сделал преобразование в черно-белое
                                          ExpandedWrap disabled
                                            //.........
                                                auto_canny(frame, edges, 0.5);
                                                edges = edges > 128;
                                            //.........

                                          Мне, собственно, для решения поставленной задачи этого хватит. Всем спасибо за помощь.

                                          Если будут у кого мысли или предложения - пишите.
                                          Сообщение отредактировано: =SAPSAN= -
                                          0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                          0 пользователей:


                                          Рейтинг@Mail.ru
                                          [ Script execution time: 0,0500 ]   [ 17 queries used ]   [ Generated: 28.03.24, 16:22 GMT ]