2010-12-21 9 views
23

¿Cómo podría recorrer una imagen usando opencv como si fuera una matriz 2D para obtener los valores rgb de cada píxel? Además, ¿sería preferible un tapete a un iplimage para esta operación?Ciclo a través de píxeles con opencv

+0

duplicado posible: http://stackoverflow.com/questions/998429/opencv-accessing-and-taking-the-square-root-of-pixels –

+0

sólo voy a utilizar esta función poco que encontró. float pixval32f (IplImage * img, int r, int c) { \t return ((float *) (img-> imageData + img-> widthStep * r)) [c]; } –

+0

http://stackoverflow.com/questions/3859222/c-negative-rgb-values-of-pixels-using-opencv/3860920#3860920 – karlphillip

Respuesta

37

cv :: Mat es preferible a IplImage porque simplifica su código

cv::Mat img = cv::imread("lenna.png"); 
for(int i=0; i<img.rows; i++) 
    for(int j=0; j<img.cols; j++) 
     // You can now access the pixel value with cv::Vec3b 
     std::cout << img.at<cv::Vec3b>(i,j)[0] << " " << img.at<cv::Vec3b>(i,j)[1] << " " << img.at<cv::Vec3b>(i,j)[2] << std::endl; 

Esto supone que tiene que utilizar los valores RGB juntos. Si no lo hace, puede usar cv :: split para obtener cada canal por separado. Vea la respuesta de etarion para el enlace con el ejemplo.

Además, en mi caso, simplemente necesita la imagen en escala de grises. Luego, puede cargar la imagen en escala de grises y acceder a ella como una matriz de uchar.

cv::Mat img = cv::imread("lenna.png",0); 
for(int i=0; i<img.rows; i++) 
    for(int j=0; i<img.cols; j++) 
     std::cout << img.at<uchar>(i,j) << std::endl; 

ACTUALIZACIÓN: Usando la división de conseguir los 3 canales

cv::Mat img = cv::imread("lenna.png"); 
std::vector<cv::Mat> three_channels = cv::split(img); 

// Now I can access each channel separately 
for(int i=0; i<img.rows; i++) 
    for(int j=0; j<img.cols; j++) 
     std::cout << three_channels[0].at<uchar>(i,j) << " " << three_channels[1].at<uchar>(i,j) << " " << three_channels[2].at<uchar>(i,j) << std::endl; 

// Similarly for the other two channels 

ACTUALIZACIÓN: Gracias a entarion para detectar el error introduje al copiar y pegar desde el cv :: ejemplo Vec3b.

+1

¿Cómo es que obtienes valores que no son enteros para la imagen? –

+1

'img.at (i, j) [0]' - esto no va a funcionar :) el '[0]' tiene que ir – etarion

+0

Llegué a esta pregunta y resolvió un problema que tenía, pero ahora Tengo la pregunta, ¿por qué :: en el funciona? ¿Por qué no funciona con el at solo? como en (0,0)? –

3

Los documentos muestran una comparación bien escrita de las diferentes formas de iterar sobre una imagen Mat here.

La manera más rápida es usar punteros estilo C. Aquí está el código copiado de los documentos:

Mat& ScanImageAndReduceC(Mat& I, const uchar* const table) 
{ 
// accept only char type matrices 
CV_Assert(I.depth() != sizeof(uchar)); 

int channels = I.channels(); 

int nRows = I.rows; 
int nCols = I.cols * channels; 

if (I.isContinuous()) 
{ 
    nCols *= nRows; 
    nRows = 1; 
} 

int i,j; 
uchar* p; 
for(i = 0; i < nRows; ++i) 
{ 
    p = I.ptr<uchar>(i); 
    for (j = 0; j < nCols; ++j) 
    { 
     p[j] = table[p[j]]; 
    } 
} 
return I; 
} 

El acceso a los elementos con el es bastante lento.

Tenga en cuenta que si su operación se puede realizar utilizando una tabla de búsqueda, la función incorporada LUT es, con mucho, la más rápida (también se describe en los documentos).

9

Desde OpenCV 3.0, hay una forma oficial y más rápida de ejecutar la función en todo el píxel en cv :: Mat.

void cv::Mat::forEach (const Functor& operation)

Si utiliza esta función, el funcionamiento es ejecuta en multi core automáticamente.

Divulgación: Soy colaborador de esta función.

+0

si esto solo resolvería el problema, el usuario de la biblioteca en realidad preferiría no tener que lidiar con los tipos. Tal vez no lo entiendo, pero de alguna manera es realmente tedioso "simplemente" leer píxeles o modificarlos !!! –

0

Si desea modificar los píxeles RGB uno por uno, el siguiente ejemplo le ayudará.

void LoopPixels(cv::Mat &img) { 
    // Accept only char type matrices 
    CV_Assert(img.depth() == CV_8U); 

    // Get the channel count (3 = rgb, 4 = rgba, etc.) 
    const int channels = img.channels(); 
    switch (channels) { 
    case 1: 
    { 
     // Single colour 
     cv::MatIterator_<uchar> it, end; 
     for (it = img.begin<uchar>(), end = img.end<uchar>(); it != end; ++it) 
      *it = 255; 
     break; 
    } 
    case 3: 
    { 
     // RGB Color 
     cv::MatIterator_<cv::Vec3b> it, end; 
     for (it = img.begin<cv::Vec3b>(), end = img.end<cv::Vec3b>(); it != end; ++it) { 
      uchar &r = (*it)[2]; 
      uchar &g = (*it)[1]; 
      uchar &b = (*it)[0]; 
      // Modify r, g, b values 
      // E.g. r = 255; g = 0; b = 0; 
     } 
     break; 
    } 
    } 
} 
Cuestiones relacionadas