OpenCV многоканальный доступ к элементам - PullRequest
50 голосов
/ 01 декабря 2009

Я пытаюсь научиться использовать новый интерфейс C ++ от openCV.

Как получить доступ к элементам многоканальной матрицы. например:

Mat myMat(size(3, 3), CV_32FC2);

for (int i = 0; i < 3; ++i)
{
    for (int j = 0; j < 3; ++j)
    {
        //myMat_at_(i,j) = (i,j);
    }
}

Какой самый простой способ сделать это? Что-то вроде cvSet2D старого интерфейса
Какой самый эффективный способ? Аналогично использованию прямых указателей в старом интерфейсе.

Спасибо

Ответы [ 5 ]

63 голосов
/ 03 декабря 2009
typedef struct elem_ {
        float f1;
        float f2;
} elem;
elem data[9] = { 0.0f };
CvMat mat = cvMat(3, 3, CV_32FC2, data );

float f1 = CV_MAT_ELEM(mat, elem, row, col).f1;
float f2 = CV_MAT_ELEM(mat, elem, row, col).f2;

CV_MAT_ELEM(mat, elem, row, col).f1 = 1212.0f;
CV_MAT_ELEM(mat, elem, row, col).f2 = 326.0f;

Обновление: для OpenCV2.0

1. выберите один тип для представления элемента

Мат (или CvMat) имеет 3 измерения: строка, столбец, канал.
Мы можем получить доступ к одному элементу (или пикселю) в матрице, указав строку и столбец.

CV_32FC2 означает, что элемент является 32-битным значением с плавающей запятой с 2 ​​каналами.
Таким образом, элемент в приведенном выше коде является одним из приемлемых представлений CV_32FC2.

Вы можете использовать другие представления, которые вам нравятся. Например:

typedef struct elem_ { float val[2];    } elem;
typedef struct elem_ { float x;float y; } elem;

OpenCV2.0 добавляет несколько новых типов для представления элемента в матрице, например:

template<typename _Tp, int cn> class CV_EXPORTS Vec // cxcore.hpp (208)

Таким образом, мы можем использовать Vec<float,2> для представления CV_32FC2 или использовать:

typedef Vec<float, 2> Vec2f; // cxcore.hpp (254)

См. Исходный код, чтобы получить больше типов, которые могут представлять ваш элемент.
Здесь мы используем Vec2f

2. получить доступ к элементу

Самый простой и эффективный способ получить доступ к элементу в классе Mat - это Mat :: at.
Имеет 4 перегрузки:

template<typename _Tp> _Tp& at(int y, int x);                // cxcore.hpp (868)
template<typename _Tp> const _Tp& at(int y, int x) const;    // cxcore.hpp (870)
template<typename _Tp> _Tp& at(Point pt);                    // cxcore.hpp (869)
template<typename _Tp> const _Tp& at(Point pt) const;        // cxcore.hpp (871)
// defineded in cxmat.hpp (454-468)

// we can access the element like this :
Mat m( Size(3,3) , CV_32FC2 );
Vec2f& elem = m.at<Vec2f>( row , col ); // or m.at<Vec2f>( Point(col,row) );
elem[0] = 1212.0f;
elem[1] = 326.0f;
float c1 = m.at<Vec2f>( row , col )[0]; // or m.at<Vec2f>( Point(col,row) );
float c2 = m.at<Vec2f>( row , col )[1];
m.at<Vec2f>( row, col )[0] = 1986.0f;
m.at<Vec2f>( row, col )[1] = 326.0f;

3. взаимодействовать со старым интерфейсом

Мат обеспечивает 2 функции преобразования:

// converts header to CvMat; no data is copied     // cxcore.hpp (829)
operator CvMat() const;                            // defined in cxmat.hpp
// converts header to IplImage; no data is copied
operator IplImage() const;

// we can interact a Mat object with old interface :
Mat new_matrix( ... );
CvMat old_matrix = new_matrix;  // be careful about its lifetime
CV_MAT_ELEM(old_mat, elem, row, col).f1 = 1212.0f;
19 голосов
/ 09 июня 2010

Vic, вы должны использовать Vec3b вместо Vec3i:

for (int i=0; i<image.rows; i++)
{
    for (int j=0; j<image.cols; j++)
    {
        if (someArray[i][j] == 0)
        {
            image.at<Vec3b>(i,j)[0] = 0;
            image.at<Vec3b>(i,j)[1] = 0;
            image.at<Vec3b>(i,j)[2] = 0;
        }
    }
}
6 голосов
/ 27 января 2012

Вы можете получить доступ к базовому массиву данных напрямую:

Mat myMat(size(3, 3), CV_32FC2);

myMat.ptr<float>(y)[2*x]; // first channel
myMat.ptr<float>(y)[2*x+1]; // second channel
1 голос
/ 13 октября 2014

зависит от типа используемого мата, если он числовой, например CV_32FC1 Вы можете использовать:

myMat.at<float>(i, j)

если это тип uchar, то вы можете получить доступ к элементу, используя

(symb.at<Vec3b>(i, j)).val[k]

где k - канал, то есть 0 для полутоновых изображений и 3 для цветных

0 голосов
/ 08 августа 2015

Лучший способ получить доступ к многоканальному массиву через API c ++ - создать указатель на конкретную строку с помощью метода ptr.

Например;

type elem = matrix.ptr<type>(i)[N~c~*j+c]

, где

  • type : тип данных (float, int, char ..)
  • i : интересующая вас строка
  • Nc : количество каналов
  • j : интересующий вас столбец
  • c : интересующий вас столбец (0-3)

Информацию о других преобразованиях в c-> c ++ можно найти по этой ссылке: Источник

...