opencv
Pixelzugriff
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 Objektcv::Vec3b
repräsentiert ein Triplett vonuchar
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)
. Diecv::Vec3f
Objekt stellt ein Triplett vonfloat
- 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})
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.