Buscar..


Observaciones

Tenga cuidado de conocer el tipo de cv::Mat que está tratando. Por ejemplo, si tiene un cv::Mat de tipo CV_8UC3 , pero acceda a él con image.at<uchar>(r,c) no se producirá ningún error, pero su programa tendrá algún comportamiento inesperado.

Acceda a valores de píxeles individuales con cv :: Mat :: at ()

Para acceder a los valores de píxeles en un objeto OpenCV cv::Mat , primero debe conocer el tipo de su matriz.

Los tipos más comunes son:

  • CV_8UC1 para imágenes de escala de grises de 1 canal de 8 bits;
  • CV_32FC1 para imágenes de escala de grises de 1 canal de punto flotante de 32 bits;
  • CV_8UC3 para imágenes en color de 8 canales y 3 canales; y
  • CV_32FC3 para imágenes de color de 3 canales de punto flotante de 32 bits.

La configuración predeterminada con cv::imread creará una matriz CV_8UC3 .

Para acceder a píxeles individuales, la forma más segura, aunque no la más eficiente, es usar el método cv::Mat::at<T>(r,c) donde r es la fila de la matriz y c es la columna . El argumento de la plantilla depende del tipo de la matriz.

Digamos que usted tiene un cv::Mat image . Según su tipo, el método de acceso y el tipo de color del píxel serán diferentes.

  • Para CV_8UC1 : uchar pixelGrayValue = image.at<uchar>(r,c) .
  • Para CV_8UC3 : cv::Vec3b pixelColor = image.at<cv::Vec3b>(r,c) . El objeto cv::Vec3b representa un triplete de valores uchar (enteros entre 0 y 255).
  • Para CV_32FC1 : float pixelGrayValue = image.at<float>(r,c) .
  • Para CV_32FC3 : cv::Vec3f pixelColor = image.at<cv::Vec3f>(r,c) . El objeto cv::Vec3f representa un triplete de valores float .

Tenga en cuenta que OpenCV representa imágenes en orden de fila mayor , como, por ejemplo, Matlab o como la convención en Álgebra. Por lo tanto, si sus coordenadas de píxeles son (x,y) , entonces accederá al píxel utilizando image.at<..>(y,x) .

Alternativamente, at<> también es compatible con el acceso a través de un solo argumento cv::Point .
En este caso, el acceso se realiza en la columna principal :

image.at<..>(cv::Point(x,y));

Eche un vistazo a la documentación de OpenCV para obtener más detalles sobre este método.

Acceso eficiente a píxeles usando cv :: Mat :: ptr puntero

Si la eficiencia es importante, una forma rápida de iterar sobre píxeles en un objeto cv::Mat es usar su ptr<T>(int r) para obtener un puntero al principio de la fila r (índice basado en 0).

Según el tipo de matriz, el puntero tendrá una plantilla diferente.

  • Para CV_8UC1 : uchar* ptr = image.ptr<uchar>(r);
  • Para CV_8UC3 : cv::Vec3b* ptr = image.ptr<cv::Vec3b>(r);
  • Para CV_32FC1 : float* ptr = image.ptr<float>(r);
  • Para CV_32FC3 : cv::Vec3f* ptr = image.ptr<cv::Vec3f>(r);

Este objeto ptr se puede usar para acceder al valor de píxel en la fila r y la columna c llamando a ptr[c] .

Para ilustrar esto, aquí hay un ejemplo donde cargamos una imagen del disco e invertimos sus canales Azul y Rojo, operando píxel por píxel:

#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>

int main(int argc, char** argv) {
    cv::Mat image = cv::imread("image.jpg", CV_LOAD_IMAGE_COLOR);

    if(!image.data) {
        std::cout << "Error: the image wasn't correctly loaded." << std::endl;
        return -1;
    }

    // We iterate over all pixels of the image
    for(int r = 0; r < image.rows; r++) {
        // We obtain a pointer to the beginning of row r
        cv::Vec3b* ptr = image.ptr<cv::Vec3b>(r);

        for(int c = 0; c < image.cols; c++) {
            // We invert the blue and red values of the pixel
            ptr[c] = cv::Vec3b(ptr[c][2], ptr[c][1], ptr[c][0]);
        }
    }

    cv::imshow("Inverted Image", image);
    cv::waitKey();

    return 0;
}

Configuración y obtención de valores de píxeles de una imagen gris en C ++

// PixelAccessTutorial.cpp : Defines the entry point for the console 
// Environment: Visual studio 2015, Windows 10
// Assumptions: Opecv is installed configured in the visual studio project
// Opencv version: OpenCV 3.1

#include "stdafx.h"
#include<opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include<string>
#include<iostream>

int main()
{

    cv::Mat imgOriginal;        // input image
    cv::Mat imgGrayscale;        // grayscale of input image

    std::cout << "Please enter an image filename : ";
    std::string img_addr;
    std::cin >> img_addr;

    std::cout << "Searching for " + img_addr << std::endl;

    imgOriginal = cv::imread(img_addr);            // open image

        if (imgOriginal.empty()) {                                    // if unable to open image
            std::cout << "error: image not read from file\n\n";        // show error message on command line
            return(0);                                                // and exit program
        }

    cv::cvtColor(imgOriginal, imgGrayscale, CV_BGR2GRAY);        // convert to grayscale

    const int channels = imgGrayscale.channels();
    printf("Number of channels = %d", channels);

    cv::Mat output ;
    imgGrayscale.copyTo(output); // Just to make sure the Mat objects are of the same size. 

    //Set the threshhold to your desired value
    uchar threshhold = 127; 

    if (channels == 1)
    {
        for (int x = 0; x<imgGrayscale.rows; x++) {
            for (int y = 0; y<imgGrayscale.cols; y++) {
                // Accesssing values of each pixel
                if (imgGrayscale.at<uchar>(x, y) >= threshhold) {
                    // Setting the pixel values to 255 if it's above the threshold
                    output.at<uchar>(x, y) = 254;
                }
                else if (imgGrayscale.at<uchar>(x, y) < threshhold) {
                    // Setting the pixel values to 255 if it's below the threshold
                    output.at<uchar>(x, y) = 0;
                }
                else {
                    // Just in case
                    printf("The value at (%d, %d) are not right. Value: %d\n", x, y, imgGrayscale.at<uchar>(x, y));
                }
            }
        }
    }
    else if (channels == 3)
    {
        // This is only for  gray scale images
        printf("\tThe image has 3 channels. The function does not support images with 3 channels.\n");
    }

    //Create windows to show image
    cv::namedWindow("Gray scale", CV_WINDOW_AUTOSIZE);    
    cv::namedWindow("Binary", CV_WINDOW_AUTOSIZE);        

    cv::imshow("Gray scale", imgGrayscale);        
    cv::imshow("Binary", output);

    cv::waitKey(0);                    // hold windows open until user presses a key

    return 0;
}

Acceso a píxeles alternativos con Matiterator

No es la mejor manera de iterar a través de los píxeles; sin embargo, es mejor que cv :: Mat :: at <T>.

Supongamos que tiene una imagen en color en su carpeta y desea iterar cada píxel de esta imagen y borrar los canales verdes y rojos (tenga en cuenta que este es un ejemplo, puede hacerlo de formas más optimizadas);

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp> 


int main(int argc, char **argv)
{

// Create a container
cv::Mat im; 

//Create a vector
cv::Vec3b *vec;

// Create an mat iterator
cv::MatIterator_<cv::Vec3b> it;

// Read the image in color format
im = cv::imread("orig1.jpg", 1);

// iterate through each pixel
for(it = im.begin<cv::Vec3b>(); it != im.end<cv::Vec3b>(); ++it)
{
    // Erase the green and red channels 
    (*it)[1] = 0;
    (*it)[2] = 0;
}


// Create a new window
cv::namedWindow("Resulting Image");

// Show the image
cv::imshow("Resulting Image", im);

// Wait for a key
cv::waitKey(0);

return 0;
}

Para compilar esto con Cmake:

cmake_minimum_required(VERSION 2.8)
project(Main)
find_package(OpenCV REQUIRED)
add_executable(Main main.cpp)
target_link_libraries(Main ${OpenCV_LIBS})

La imagen original: introduzca la descripción de la imagen aquí

La imagen procesada: introduzca la descripción de la imagen aquí

Tenga en cuenta que no tocamos sólo el canal azul.

Para más información: http://docs.opencv.org/2.4/opencv_tutorials.pdf Página: 145

Acceso a píxeles en el tapete

El acceso de píxeles individuales en la estructura de la matriz OpenCV se puede lograr de múltiples maneras. Para entender cómo acceder, es mejor aprender primero los tipos de datos.

Estructuras básicas explica los tipos de datos básicos. En breve, CV_<bit-depth>{U|S|F}C(<number_of_channels>) es la estructura básica de un tipo. Junto con eso, es importante entender las estructuras de Vec .

typedef Vec<type, channels> Vec< channels>< one char for the type>

donde type es uno de uchar, short, int, float, double y los caracteres para cada tipo son b, s, i, f, d , respectivamente.

Por ejemplo, Vec2b indica un unsigned char vector of 2 channels .

Considere Mat mat(R,C,T) donde R es #rows, C es #cols y T es tipo. Algunos ejemplos para acceder a la coordenada (i, j) de mat son:

2D:

If the type is CV_8U or CV_8UC1 ---- //they are alias
mat.at<uchar>(i,j) // --> This will give char value of index (i,j)
//If you want to obtain int value of it
(int)mat.at<uchar>(i,j)

If the type is CV_32F or CV_32FC1 ---- //they are alias
mat.at<float>(i,j) // --> This will give float value of index (i,j)

3D:

If the type is CV_8UC2 or CV_8UC3 or more channels
mat.at<Vec2b/Vec3b>(i,j)[k] // note that (k < #channels)
//If you want to obtain int value of it
(int)mat.at<uchar>(i,j)[k] 

If the type is CV_64FC2 or CV_64FC3 
mat.at<Vec2d/Vec3d>(i,j)[k] // note that k < #channels

Tenga en cuenta que es muy importante ingresar el tipo correcto en <...> , de lo contrario, puede tener un error de tiempo de ejecución o resultados no deseados.



Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow