수색…


비고

당신이 다루고있는 cv::Mat 의 타입을주의해야한다. 예를 들어 CV_8UC3 유형의 cv::Mat 가 있지만 image.at<uchar>(r,c) 하여 액세스하는 경우 오류는 발생하지 않지만 프로그램에 예기치 않은 동작이 발생합니다.

cv :: Mat :: at를 사용하여 개별 픽셀 값에 액세스 ()

OpenCV cv::Mat 객체의 픽셀 값에 액세스하려면 먼저 행렬의 유형 을 알아야합니다.

가장 일반적인 유형은 다음과 같습니다.

  • 8 비트 1 채널 그레이 스케일 이미지의 경우 CV_8UC1 ;
  • 32 비트 부동 소수점 1 채널 그레이 스케일 이미지 용 CV_32FC1 ;
  • 8 비트 3 채널 컬러 이미지의 경우 CV_8UC3 ; 과
  • 32 비트 부동 소수점 3 채널 컬러 이미지 용 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::Vec3b 나타냅니다.
  • CV_32FC1 : float pixelGrayValue = image.at<float>(r,c) .
  • CV_32FC3 : cv::Vec3f pixelColor = image.at<cv::Vec3f>(r,c) . cv::Vec3f 객체는 float 값의 세 cv::Vec3f 나타냅니다.

OpenCV는 Matlab과 같은 우선 순위의 이미지를 나타내거나 대수의 규칙으로 사용됩니다. 따라서 픽셀 좌표가 (x,y) 이면 image.at<..>(y,x) 사용하여 픽셀에 액세스합니다.

또는 at<> 에서 단일 cv::Point 인수를 통해 액세스를 지원할 수도 있습니다.
이 경우 액세스는 column-major로 수행됩니다.

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 객체를 사용하여 ptr[c] 호출하여 행 r 및 열 c 의 픽셀 값에 액세스 할 수 있습니다.

이것을 설명하기 위해 디스크에서 이미지를로드하고 Blue 및 Red 채널을 반전하여 픽셀 단위로 작동시키는 예가 있습니다.

#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 ++에서 Gray 이미지의 픽셀 값 설정 및 가져 오기

// 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})

원본 이미지 : 여기에 이미지 설명을 입력하십시오.

처리 된 이미지 : 여기에 이미지 설명을 입력하십시오.

Blue 채널 만 건드리지는 않습니다.

자세한 내용은 http://docs.opencv.org/2.4/opencv_tutorials.pdf 페이지 : 145 페이지를 참조하십시오.

매트의 픽셀 액세스

OpenCV 매트 구조의 개별 픽셀 액세스는 여러 가지 방법으로 수행 할 수 있습니다. 액세스하는 방법을 이해하려면 먼저 데이터 유형을 배우는 것이 좋습니다.

기본 구조 는 기본 데이터 유형을 설명합니다. 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 channelsunsigned char vector of 2 channels 나타냅니다.

Mat mat(R,C,T) 생각해보십시오. 여기서 R은 #rows이고 C는 #cols이고 T는 유형입니다. mat 의 (i, j) 좌표에 액세스하기위한 몇 가지 예는 다음과 같습니다.

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