OpenCV Segfaults при создании мата - PullRequest
0 голосов
/ 19 марта 2020

У меня есть код, который создает пару пирамид изображений, хранящихся как std::vector<cv::Mat_<T>>. Одна из пирамид представляет собой двоичную маску, хранящуюся в массиве без знака. Эта пирамида, кажется, создает хорошо. Другая пирамида - это пирамида данных с плавающей точкой. Он создается с использованием только данных на предыдущих уровнях, где маска истинна.

Моя проблема возникает, когда я размещаю данные для этих пирамид. Я выделяю пустое поле данных и затем перемещаю его в вектор (хотя я могу использовать cv::Mat::zeros). Сегфоут происходит при первоначальном размещении. Еще более странно, что это не происходит на первой итерации. В чем причина segfault ???

Пример кода:

template <typename T>
auto CreateMaskedPyramid(const cv::Mat_<unsigned char>& input_mask,
                         const cv::Mat_<T>& input_data, int minimum_size) {
  assert(input_mask.cols == input_data.cols);
  assert(input_mask.rows == input_data.rows);
  std::vector<cv::Mat_<unsigned char>> masks(1);
  input_mask.copyTo(masks.back());
  std::vector<cv::Mat_<T>> datas(1);
  input_data.copyTo(datas.back());
  cv::Size size = input_data.size();
  while (std::min(masks.back().rows, masks.back().cols) / 2 > minimum_size) {
    size = size / 2;
    masks.emplace_back();
    datas.emplace_back();
    masks.back() = cv::Mat_<unsigned char>(size, static_cast<unsigned char>(0));
    cv::Mat_<T> temp(size, static_cast<T>(0));
    datas.back() = std::move(temp);
    const auto& previous_mask = masks.at(masks.size() - 2);
    const auto& previous_data = datas.at(masks.size() - 2);

    for (int y = 0; y < masks.back().rows; y++) {
      for (int x = 0; x < masks.back().cols; x++) {
        unsigned char num_valid = 0;
        if (previous_mask.at<float>(y * 2, x * 2) > 0) {
          num_valid += 1;
          datas.back().template at<T>(y, x) += previous_data.template at<T>(y * 2, x * 2);
        }
        if (previous_mask.at<float>(y * 2, x * 2 + 1) > 0) {
          num_valid += 1;
          datas.back().template at<T>(y, x) += previous_data.template at<T>(y * 2, x * 2 + 1);
        }
        if (previous_mask.at<float>(y * 2 + 1, x * 2) > 0) {
          num_valid += 1;
          datas.back().template at<T>(y, x) += previous_data.template at<T>(y * 2 + 1, x * 2);
        }
        if (previous_mask.at<float>(y * 2 + 1, x * 2 + 1) > 0) {
          num_valid += 1;
          datas.back().template at<T>(y, x) += previous_data.template at<T>(y * 2 + 1, x * 2 + 1);
        }

        if (num_valid != 0) {
          datas.back().template at<T>(y, x) /= static_cast<float>(num_valid);
        } else {
          datas.back().template at<T>(y, x) = 0.0f;
        }
        masks.back().template at<T>(y, x) = num_valid > 0 ? 255 : 0;
      }
    }
  }
  return std::make_tuple(std::move(masks), std::move(datas));
}

int main(int argc, char** argv) {
  assert(argc > 1);
  auto fname = std::string(argv[1]);
  cv::Mat image = cv::imread(fname, cv::IMREAD_GRAYSCALE);
  cv::Mat_<unsigned char> mask;
  cv::threshold(image, mask, 127, 255, cv::THRESH_BINARY);
  cv::Mat_<float> data;
  image.convertTo(data, data.type());
  auto [mask_pyramid, data_pyramid] = CreateMaskedPyramid<float>(image, data, 64);
  return mask_pyramid.size() == data_pyramid.size() ? 0 : 255;
}

При использовании GDB трассировка стека переходит к cv :: Mat :: create, вызываемому из cv::Mat_<T> temp(size, static_cast<T>(0));

...