Ошибка времени выполнения при присвоении значения элемента cv::Mat с использованием cv::Mat::at

В следующем коде я хотел бы присвоить значения элементам переменной Mat в цикле. Я получаю ошибку времени выполнения ниже.

pair<Mat, Mat> meshgrid(vector<int> x, vector<int> y) {

    int sx = (int)x.size();
    int sy = (int)y.size();
    
    Mat xmat = Mat::ones(sy, sx, CV_16U);
    Mat ymat = Mat::ones(sy, sy, CV_16U);

    for (int i = 0; i < sx; i++) {
        for (int j = 0; j < sy; j++) {
            xmat.at<int>(i, j) = j;  // <------- here is place of error.
            cout << j << "\t";
        }
        cout << endl;
    }

    for (int i = 0; i < sx; i++) {
        for (int j = 0; j < sy; j++) {
            ymat.at<int>(i, j) = i;  // <------- here is place of error.
            cout << j << "\t";
        }
        cout << endl;
    }

    return make_pair(xmat, ymat);
}

Эта картинка при отладке;

Ошибка времени выполнения при присвоении значения элемента cv::Mat с использованием cv::Mat::at

Это ошибка времени выполнения, которую я получаю:

OpenCV(...) Error: Assertion failed
(((((sizeof(size_t)<<28)|0x8442211) >> ((traits::Depth<_Tp>::value) &
((1 << 3) - 1))*4) & 15) == elemSize1()) in cv::Mat::at, file
...\include\opencv2\core\mat.inl.hpp, line 1108

Спасибо за ваши ответы.

Вы программируете на C++. Пожалуйста, не добавляйте другие нерелевантные языковые теги.

Some programmer dude 12.05.2022 12:37

меняя ymat.at<int>(i, j) = i; на ymat.at<uchar>cv::Point(i, j) = i;

Yunus Temurlenk 12.05.2022 14:55

@YunusTemurlenk - Я думаю, что помимо использования at в коде есть еще некоторые проблемы. Смотрите мой ответ ниже.

wohlstad 12.05.2022 15:03

@wohlstad Это единственная ошибка, которую я видел. но ваш ответ указывает и на другие ошибки. Я подниму твой ответ;)

Yunus Temurlenk 12.05.2022 15:47
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
4
51
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я предполагаю, что вы хотели сгенерировать вывод, аналогичный numpy.meshgrid и Матлаб meshgrid.

В вашем коде есть несколько ошибок:

  1. cv::Mat инициализируется типом CV_16U (т. е. 16-битным значением без знака), но когда вы получаете доступ к элементам с помощью at, вы используете int (32-битное знаковое значение). Вы должны изменить его на at<unsigned short> (или изменить тип cv::Mat на 32-битный знак - CV_32S).
  2. Вы инициализировали cv::Mat неправильными размерами: xmat имеет размер (sy, sx), но ymat имеет размер (sy, sy).
  3. Индексы (строка, столбец), которые вы использовали для доступа к матовым элементам, были неверными. Чтобы упростить правильное использование, я изменил названия измерений на rows, cols, и индексы цикла к iRow, iCol.
  4. Значения в матрицах должны исходить из значений векторов x и y (а не индексов).

См. обновленный код ниже (и примечания после него относительно изменений):

#include <opencv2/core/core.hpp>
#include <vector>
#include <iostream>

std::pair<cv::Mat, cv::Mat> meshgrid(std::vector<unsigned short> const & x, std::vector<unsigned short> const & y)
{
    int cols = static_cast<int>(x.size());
    int rows = static_cast<int>(y.size());
    cv::Mat xmat(rows, cols, CV_16U);
    cv::Mat ymat(rows, cols, CV_16U);

    for (int iRow = 0; iRow < rows; ++iRow) {
        auto * pRowData = xmat.ptr<unsigned short>(iRow);
        for (int iCol = 0; iCol < cols; ++iCol) {
            pRowData[iCol] = x[iCol];
            std::cout << pRowData[iCol] << "\t";
        }
        std::cout << std::endl;
    }

    std::cout << std::endl;

    for (int iRow = 0; iRow < rows; ++iRow) {
        auto * pRowData = ymat.ptr<unsigned short>(iRow);
        for (int iCol = 0; iCol < cols; ++iCol) {
            pRowData[iCol] = y[iRow];
            std::cout << pRowData[iCol] << "\t";
        }
        std::cout << std::endl;
    }

    return std::make_pair(std::move(xmat), std::move(ymat));
}

int main()
{
    std::vector<unsigned short> xxx{ 1,2 };
    std::vector<unsigned short> yyy{ 10,11,12 };
    auto p = meshgrid(xxx, yyy);
    return 0;
}

Выход:

1       2
1       2
1       2

10      10
11      11
12      12

Некоторые примечания:

  1. Возможно, я неправильно понял, какие значения вы хотели установить в cv::Mat. Но, по крайней мере, теперь у вас есть код, который не дает сбоев. Вы можете изменить присвоенные значения по своему усмотрению.
  2. Использование at для доступа к cv::Mat элементам один за другим очень неэффективно, потому что at содержит некоторые проверки для каждого доступа. Гораздо эффективнее использовать метод cv::Matptr, который дает вам указатель на данные строки. Затем вы можете использовать этот указатель для более эффективного обхода строки - см. выше
  3. В любом методе более эффективно проходить cv::Mat одну строку за другой (а не столбец за столбцом). Это заставляет вас обращаться к непрерывной памяти и уменьшает количество промахов кеша.
  4. В вашем реальном коде лучше отделить вычисления от ввода/вывода. Поэтому лучше, если ваша функция meshgrid будет создавать только матрицы. Распечатайте их снаружи, если вам нужно.
  5. Не нужно инициализировать cv::Mat единицами, потому что сразу после этого мы устанавливаем значения для всех элементов.
  6. В моем коде x и y передаются функции по константной ссылке. Это более эффективно (избегайте копирования), а также заставляет компилятор проверять, что векторы не изменены.
  7. Лучше избегать using namespace std - см. здесь Почему «используется пространство имен std;» считается плохой практикой?. По аналогичным причинам я также рекомендую избегать using namespace cv.

Спасибо, ваше решение работает, это из-за несоответствия в типе данных, который получает cv::Mat.

Nurullah Çelebi 12.05.2022 16:12

Другие вопросы по теме