Suche…


Bemerkungen

Seien Sie vorsichtig mit dem Typ von cv::Mat Sie sich befassen. Wenn Sie beispielsweise eine cv::Mat vom Typ CV_8UC3 , aber mit image.at<uchar>(r,c) zugreifen, image.at<uchar>(r,c) kein Fehler auf, aber Ihr Programm wird unerwartet auftreten.

Greifen Sie mit cv :: Mat :: at auf einzelne Pixelwerte zu ()

Um auf Pixelwerte in einem OpenCV-Objekt cv::Mat zugreifen zu können, müssen Sie zunächst den Typ Ihrer Matrix kennen.

Die häufigsten Arten sind:

  • CV_8UC1 für 8-Bit-1-Kanal-Graustufenbilder;
  • CV_32FC1 für 32-Bit-Fließkomma-1-Kanal-Graustufenbilder;
  • CV_8UC3 für 8-Bit-3-Kanal-Farbbilder; und
  • CV_32FC3 für 32-Bit-Fließkomma-3-Kanal-Farbbilder.

Die Standardeinstellung mit cv::imread erstellt eine CV_8UC3 Matrix.

Für den Zugriff auf einzelne Pixel, die sicherste Art und Weise, wenn auch nicht die effizienteste, ist die Verwendung cv::Mat::at<T>(r,c) Verfahren , wobei r die Reihe der Matrix ist und c ist die Spalte. Das Vorlagenargument hängt vom Typ der Matrix ab.

Nehmen wir an, Sie haben ein cv::Mat image . Je nach Typ unterscheiden sich die Zugriffsmethode und der Pixelfarbtyp.

  • Für CV_8UC1 : uchar pixelGrayValue = image.at<uchar>(r,c) .
  • Für CV_8UC3 : cv::Vec3b pixelColor = image.at<cv::Vec3b>(r,c) . Das Objekt cv::Vec3b repräsentiert ein Triplett von uchar Werten (Ganzzahlen zwischen 0 und 255).
  • Für CV_32FC1 : float pixelGrayValue = image.at<float>(r,c) .
  • Für CV_32FC3 : cv::Vec3f pixelColor = image.at<cv::Vec3f>(r,c) . Die cv::Vec3f Objekt stellt ein Triplett von float - Werten.

Man beachte , dass OpenCV Bilder in Reihenhauptordnung darstellt, wie, zB Matlab oder als die Konvention in Algebra. Wenn Ihre Pixelkoordinaten (x,y) , können Sie das Pixel also mit image.at<..>(y,x) .

Alternativ können Sie at<> auch den Zugriff über ein einzelnes cv::Point Argument unterstützen.
In diesem Fall erfolgt der Zugriff in der Spalte major :

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

In der OpenCV-Dokumentation finden Sie weitere Informationen zu dieser Methode.

Effizienter Pixelzugriff mit cv :: Mat :: ptr Zeiger

Wenn die Effizienz wichtig ist, können Sie Pixel in einem cv::Mat Objekt schnell durchlaufen, indem Sie die Methode ptr<T>(int r) verwenden, um einen Zeiger auf den Anfang der Zeile r (0-basierter Index) zu erhalten.

Je nach Matrixtyp hat der Zeiger eine andere Vorlage.

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

Dieses ptr Objekt kann dann verwendet werden, um auf den Pixelwert in Zeile r und Spalte c zuzugreifen, indem ptr[c] .

Um dies zu veranschaulichen, hier ein Beispiel, bei dem wir ein Bild von der Festplatte laden und seine blauen und roten Kanäle umkehren, wobei wir Pixel für Pixel arbeiten:

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

Festlegen und Abrufen von Pixelwerten eines Gray-Bildes in 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;
}

Alternativer Pixelzugriff mit Matiterator

Dies ist nicht der beste Weg, um durch die Pixel zu iterieren. Es ist jedoch besser als cv :: Mat :: in <T>.

Nehmen wir an, Sie haben ein Farbbild in Ihrem Ordner, und Sie möchten alle Pixel dieses Bildes durchlaufen und grüne und rote Kanäle löschen (Beachten Sie, dass dies ein Beispiel ist.

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

Um dies mit Cmake zu kompilieren:

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

Das ursprüngliche Bild: Geben Sie hier die Bildbeschreibung ein

Das verarbeitete Bild: Geben Sie hier die Bildbeschreibung ein

Beachten Sie, dass wir nicht nur den Blaukanal berühren.

Weitere Informationen finden Sie unter: http://docs.opencv.org/2.4/opencv_tutorials.pdf Seite: 145

Pixelzugriff in Mat

Ein einzelner Pixelzugriff in der OpenCV-Mat-Struktur kann auf mehrere Arten erreicht werden. Um den Zugriff zu verstehen, sollten Sie zuerst die Datentypen lernen.

Grundstrukturen erläutert die grundlegenden Datentypen. Kurz CV_<bit-depth>{U|S|F}C(<number_of_channels>) ist CV_<bit-depth>{U|S|F}C(<number_of_channels>) die Grundstruktur eines Typs. Daneben ist es wichtig, die Vec Strukturen zu verstehen.

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

Dabei ist Typ einer der uchar, short, int, float, double und die Zeichen für jeden Typ sind b, s, i, f, d .

Beispielsweise gibt Vec2b einen unsigned char vector of 2 channels Zeichenvektor unsigned char vector of 2 channels .

Betrachten Sie Mat mat(R,C,T) wobei R # Zeilen ist, C # Cols und T der Typ ist. Einige Beispiele für den Zugriff auf die (i, j) -Koordinate von mat sind:

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

Beachten Sie, dass es sehr wichtig ist, den richtigen Typ in <...> einzugeben. Andernfalls können Laufzeitfehler oder unerwünschte Ergebnisse auftreten.



Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow