Определение типа шаблона при доступе к элементам OpenCV Mat - PullRequest
6 голосов
/ 20 января 2011

Я использую следующий код для добавления шума к изображению (прямо из ссылки на OpenCV, стр. 449 - объяснение cv::Mat::begin):

void
simulate_noise(Mat const &in, double stddev, Mat &out)
{
    cv::Size s = in.size();
    vector<double> noise = generate_noise(s.width*s.height, stddev);

    typedef cv::Vec<unsigned char, 3> V4;
    cv::MatConstIterator_<V4> in_itr = in.begin<V4>();
    cv::MatConstIterator_<V4> in_end = in.end<V4>();
    cv::MatIterator_<V4> out_itr = out.begin<V4>();
    cv::MatIterator_<V4> out_end = out.end<V4>();

    for (; in_itr != in_end && out_itr != out_end; ++in_itr, ++out_itr)
    {
        int noise_index = my_rand(noise.size());
        for (int j = 0; j < 3; ++j)
            (*out_itr)[j] = (*in_itr)[j] + noise[noise_index];
    }
}

Ничего слишком сложного:

  • in и out выделяются cv::Mat объекты одинаковых размеров и типа
  • итерируют по входному изображению in
  • в каждой позициивыберите случайное значение из noise (my_rand(int n) возвращает случайное число в [0..n-1]
  • , суммируйте пиксель из in со значением случайного шума
  • , поместите результат суммирования вout

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

typedef cv::Vec<unsigned char, 3> V4;

В нем жестко заданы две вещи:

  1. Изображения имеют 3 канала
  2. Глубина канала 8bpp

Если я получу typedef неправильно (например, неверная глубина канала или неправильное количество каналов), то моя программаsegfaults. Первоначально я использовал typedef cv::Vec<unsigned char, 4> V4 для обработки изображений с произвольным числом каналов (максимальный OpenCVsupport - это 4), но это вызвало ошибку segfault.

Можно ли как-то избежать жесткого кодирования двух вещей выше?В идеале я хочу что-то общее, как:

typedef cv::Vec<in.type(), in.size()> V4;

Ответы [ 3 ]

3 голосов
/ 09 февраля 2011

Я знаю, что это поздно. Однако реальное решение вашей проблемы - использовать функциональность OpenCV, чтобы делать то, что вы хотите.

  1. создайте вектор шума, как вы уже сделали (или используйте функции, которые предоставляет OpenCV подсказка! )
  2. случайный вектор шума, поэтому вам не нужен индивидуальный noise_index для каждого пикселя; или заранее создать вектор случайного шума
  3. построить заголовок матрицы вокруг вашего перемешанного / случайного вектора: cv::Mat_<double>(noise);
  4. использовать матричные операции для вычисления: out = in + noise; или cv::add(in, noise, out);
  5. PROFIT!

Еще одним преимуществом этого метода является то, что OpenCV может использовать многопоточность, SSE или что-либо еще для ускорения этой операции с массивными элементами, чего у вас нет. Ваш код проще, чище, и OpenCV сделает всю неприятную обработку типов за вас.

2 голосов
/ 20 января 2011

Проблема заключается в том, что вам нужно определить тип и количество каналов во время выполнения, но шаблоны нуждаются в информации во время компиляции.Вы можете избежать жесткого кодирования количества каналов, используя cv::split и cv::merge или изменив итерацию на

for(int row = 0; row < in.rows; ++row) {
    unsigned char* inp  = in.ptr<unsigned char>(row);
    unsigned char* outp = out.ptr<unsigned char>(row);
    for (int col = 0; col < in.cols; ++col) {
        for (int c = 0; c < in.channels(); ++c) {
            *outp++ = *inp++ + noise();
        }
    }
}

Если вы хотите избавиться от зависимости типа, я быпредложите поместить вышеупомянутое в шаблонную функцию и вызывать ее из вашей функции, в зависимости от типа матрицы.

1 голос
/ 20 января 2011

Они жестко запрограммированы, потому что производительность лучше.

В OpenCV1.x есть cvGet2D (), который можно использовать здесь, так как Mat может быть приведен как IplImage. Но это медленно, так как каждый раз, когда вы получаете доступ к пикселю, функция узнает тип, размер и т. Д. Особенно неэффективно в циклах.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...