Поиск…


замечания

Будьте осторожны, чтобы знать тип cv::Mat вы имеете дело. Например, если у вас есть cv::Mat типа CV_8UC3 , но получите доступ к нему с помощью image.at<uchar>(r,c) ошибка не произойдет, но ваша программа будет иметь некоторое неожиданное поведение.

Доступ к отдельным значениям пикселей с помощью cv :: Mat :: at ()

Чтобы получить доступ к значениям пикселей в объекте cv::Mat OpenCV, вам сначала нужно узнать тип вашей матрицы.

Наиболее распространенными типами являются:

  • CV_8UC1 для 8-битных одноканальных изображений в оттенках серого;
  • CV_32FC1 для 32-битных изображений с CV_32FC1 1-канальным полутоном;
  • CV_8UC3 для 8-битных трехканальных цветных изображений; а также
  • CV_32FC3 для 32-битных CV_32FC3 цветных изображений с плавающей запятой.

Значение по умолчанию cv::imread создаст матрицу CV_8UC3 .

Для доступа к отдельным пикселям самым безопасным способом, хотя и не самым эффективным, является использование метода cv::Mat::at<T>(r,c) где r - строка матрицы, а c - столбец . Аргумент шаблона зависит от типа матрицы.

Скажем, у вас есть изображение cv::Mat image . Согласно его типу, метод доступа и тип цвета пикселей будут разными.

  • Для CV_8UC1 : uchar pixelGrayValue = image.at<uchar>(r,c) .
  • Для CV_8UC3 : cv::Vec3b pixelColor = image.at<cv::Vec3b>(r,c) . Объект cv::Vec3b представляет собой триплет значений uchar (целые числа от 0 до 255).
  • Для CV_32FC1 : float pixelGrayValue = image.at<float>(r,c) .
  • Для CV_32FC3 : cv::Vec3f pixelColor = image.at<cv::Vec3f>(r,c) . Объект cv::Vec3f представляет собой триплет значений float .

Обратите внимание, что OpenCV представляет изображения в строчном порядке, например, например, Matlab или как соглашение в алгебре. Таким образом, если ваши координаты пикселей (x,y) , то вы получите доступ к пикселю, используя image.at<..>(y,x) .

Кроме того, at<> также поддерживается доступ через один аргумент cv::Point .
В этом случае доступ осуществляется в столбце :

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

Взгляните на документацию OpenCV для получения более подробной информации об этом методе.

Эффективный доступ к пикселям с использованием cv :: Mat :: ptr указатель

Если эффективность важна, быстрый способ итерации по пикселям в объекте cv::Mat заключается в использовании его метода ptr<T>(int r) для получения указателя на начало строки r (индекс на основе 0).

В соответствии с типом матрицы указатель будет иметь другой шаблон.

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

Этот объект ptr можно затем использовать для доступа к значению пикселя в строке r и столбце c , вызывая ptr[c] .

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

#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;
}

Настройка и получение значений пикселей серого изображения в 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;
}

Альтернативный доступ к пикселям с помощью Matiterator

Это не лучший способ итерации через пиксели; однако это лучше, чем cv :: Mat :: at <T>.

Предположим, у вас есть цветное изображение в вашей папке, и вы хотите перебирать все пиксели этого изображения и стирать зеленые и красные каналы (обратите внимание, что это пример, вы можете сделать это более оптимизированными способами);

#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;
}

Чтобы скомпилировать это с помощью Cmake:

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

Исходное изображение: введите описание изображения здесь

Обработанное изображение: введите описание изображения здесь

Обратите внимание: мы не трогаем только синий канал.

Для получения дополнительной информации: http://docs.opencv.org/2.4/opencv_tutorials.pdf Страница: 145

Доступ к пикселям в матрице

Индивидуальный доступ к пикселям в структуре Matrix OpenCV может быть достигнут несколькими способами. Чтобы понять, как получить доступ, лучше сначала изучить типы данных.

Основные структуры объясняют основные типы данных. CV_<bit-depth>{U|S|F}C(<number_of_channels>) , CV_<bit-depth>{U|S|F}C(<number_of_channels>) является базовой структурой типа. Наряду с этим важно понимать структуры Vec .

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

где type - один из uchar, short, int, float, double а символы для каждого типа - b, s, i, f, d соответственно.

Например, Vec2b указывает unsigned char vector of 2 channels .

Рассмотрим Mat mat(R,C,T) где R является #rows, C является #cols и T является типом. Некоторые примеры для доступа к координате (i, j) mat :

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

Обратите внимание, что очень важно ввести правильный тип в <...> , в противном случае вы можете иметь ошибку времени выполнения или нежелательные результаты.



Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow