openCV에서 특정 픽셀 RGB 값에 액세스


78

인터넷과 stackoverflow를 철저히 검색했지만 내 질문에 대한 답을 찾지 못했습니다.

OpenCV에서 특정 (x, y 좌표로 주어진) 픽셀의 RGB 값을 어떻게 얻거나 설정할 수 있습니까? 중요한 것은 C ++로 작성 중이며 이미지는 cv :: Mat 변수에 저장됩니다. IplImage () 연산자가 있다는 것을 알고 있지만 IplImage는 C API에서 온다는 것을 아는 한 사용하기에 그리 편하지 않습니다.

예, OpenCV 2.2 스레드 이미 픽셀 액세스 가 있다는 것을 알고 있지만 흑백 비트 맵에 관한 것뿐입니다.

편집하다:

모든 답변에 감사드립니다. 픽셀의 RGB 값을 가져 오거나 설정하는 방법에는 여러 가지가 있습니다. 친한 친구에게서 아이디어가 하나 더 생겼습니다. Benny에게 감사합니다! 매우 간단하고 효과적입니다. 어느 것을 선택 하느냐의 문제라고 생각합니다.

Mat image;

(...)

Point3_<uchar>* p = image.ptr<Point3_<uchar> >(y,x);

그런 다음 다음을 사용하여 RGB 값을 읽고 쓸 수 있습니다.

p->x //B
p->y //G
p->z //R

답변:


99

다음을 시도하십시오.

cv::Mat image = ...do some stuff...;

image.at<cv::Vec3b>(y,x); 유형의 RGB (BGR로 주문 될 수 있음) 벡터를 제공합니다. cv::Vec3b

image.at<cv::Vec3b>(y,x)[0] = newval[0];
image.at<cv::Vec3b>(y,x)[1] = newval[1];
image.at<cv::Vec3b>(y,x)[2] = newval[2];

Ipl Image를 사용하여 동일한 것을 제안 할 수 있습니까?
Frankenstein

1
확실한! 확인 cvGet2D docs.opencv.org/modules/core/doc/…
Boaz

IplImage ..를 사용하여 동일한 글을 작성하는 데 도움을 줄 수 있습니까?
Frankenstein 2013

cvGet2D에 대한 내 의견을 참조하십시오 @Frankenstein
보아스

2
@Ahmad typedef Vec <uchar, 3> Vec3b; -3 uchars (0-255)의 벡터를 의미하며 RGB의 각 구성 요소 (The R, G 및 B)는 0에서 255 사이의 숫자 값을 사용하여 표현됩니다. 이미지의 "at"방법은 다음과 같습니다. 2 차원 행렬을 나타내는 클래스 인 cv :: Mat의 메서드. 셀 유형이 CV_8UC3 인 cv :: Mat이라고 말하면 행렬의 각 셀이 각각 8 비트의 3 개 채널 안에 들어간다는 것을 의미합니다. image.at <cv :: Vec3b) (y, x) 우리는 실제로- " 전지 X를 받기, Y 3 uchars의 벡터와 행렬 매트의 "벡터 각 셀은, 상기 채널 중 하나를 나타냄
보아즈

18

낮은 수준의 방법은 행렬 데이터에 직접 액세스하는 것입니다. RGB 이미지 (OpenCV가 일반적으로 BGR로 저장한다고 생각 함)에서 cv :: Mat 변수가 호출되었다고 가정하면 다음과 같이 frame위치 ( x, y) (왼쪽 상단에서) 에서 파란색 값을 얻을 수 있습니다 .

frame.data[frame.channels()*(frame.cols*y + x)];

마찬가지로 B, G 및 R을 얻으려면 :

uchar b = frame.data[frame.channels()*(frame.cols*y + x) + 0];    
uchar g = frame.data[frame.channels()*(frame.cols*y + x) + 1];
uchar r = frame.data[frame.channels()*(frame.cols*y + x) + 2];

이 코드는 보폭이 이미지의 너비와 같다고 가정합니다.


감사합니다. RGB 값을 읽을 때 작동합니다. 나는 운없이 frame.data [...]를 특정 값으로 설정하려고 시도했지만 Boaz.Jan이 제공 한 솔루션이 작동하고 있습니다.
Wookie88

@aaedvarkk 놀랍습니다, 당신은 내 하루를 구했습니다!
Jumabek Alikhanov

2
그래야하지 frame.data[frame.channels()*(frame.cols*y + x)];않습니까?
Shmil The Cat

2

이러한 문제가있는 사람들에게는 코드 조각이 더 쉽습니다. 내 코드를 공유하고 직접 사용할 수 있습니다. OpenCV는 픽셀을 BGR로 저장합니다.

cv::Mat vImage_; 

if(src_)
{
    cv::Vec3f vec_;

    for(int i = 0; i < vHeight_; i++)
        for(int j = 0; j < vWidth_; j++)
        {
            vec_ = cv::Vec3f((*src_)[0]/255.0, (*src_)[1]/255.0, (*src_)[2]/255.0);//Please note that OpenCV store pixels as BGR.

            vImage_.at<cv::Vec3f>(vHeight_-1-i, j) = vec_;

            ++src_;
        }
}

if(! vImage_.data ) // Check for invalid input
    printf("failed to read image by OpenCV.");
else
{
    cv::namedWindow( windowName_, CV_WINDOW_AUTOSIZE);
    cv::imshow( windowName_, vImage_); // Show the image.
}

0

현재 버전에서는 cv::Mat::at함수가 3 차원 을 처리 할 수 있습니다 . 따라서 Mat객체의 m경우 m.at<uchar>(0,0,0)작동합니다.


5
실제로이 버전은 at다중 채널 매트에서 작동하지 않습니다. 2 차원 다중 채널 Mat가 3 차원 단일 채널 Mat와 동일한 메모리 레이아웃을 가지고 있음에도 불구하고 Mat 헤더의 차이로 인해 메서드에서 예외가 발생합니다.
Andrey Kamaev

0
uchar * value = img2.data; //Pointer to the first pixel data ,it's return array in all values 
int r = 2;
for (size_t i = 0; i < img2.cols* (img2.rows * img2.channels()); i++)
{

        if (r > 2) r = 0;

        if (r == 0) value[i] = 0;
        if (r == 1)value[i] =  0;
        if (r == 2)value[i] = 255;

        r++;
}

-5
const double pi = boost::math::constants::pi<double>();

cv::Mat distance2ellipse(cv::Mat image, cv::RotatedRect ellipse){
    float distance = 2.0f;
    float angle = ellipse.angle;
    cv::Point ellipse_center = ellipse.center;
    float major_axis = ellipse.size.width/2;
    float minor_axis = ellipse.size.height/2;
    cv::Point pixel;
    float a,b,c,d;

    for(int x = 0; x < image.cols; x++)
    {
        for(int y = 0; y < image.rows; y++) 
        {
        auto u =  cos(angle*pi/180)*(x-ellipse_center.x) + sin(angle*pi/180)*(y-ellipse_center.y);
        auto v = -sin(angle*pi/180)*(x-ellipse_center.x) + cos(angle*pi/180)*(y-ellipse_center.y);

        distance = (u/major_axis)*(u/major_axis) + (v/minor_axis)*(v/minor_axis);  

        if(distance<=1)
        {
            image.at<cv::Vec3b>(y,x)[1] = 255;
        }
      }
  }
  return image;  
}

이것은 질문에 어떻게 대답합니까?
rayryeng
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.