C++ 使用 opencv 循环像素

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4504687/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 15:34:20  来源:igfitidea点击:

Cycle through pixels with opencv

c++loopsopencvpixel

提问by a sandwhich

How would I be able to cycle through an image using opencv as if it were a 2d array to get the rgb values of each pixel? Also, would a mat be preferable over an iplimage for this operation?

我如何能够使用 opencv 循环浏览图像,就好像它是一个二维数组来获取每个像素的 rgb 值?另外,对于此操作,mat 是否比 iplimage 更可取?

采纳答案by etarion

If you use C++, use the C++ interface of opencv and then you can access the members via http://docs.opencv.org/2.4/doc/tutorials/core/how_to_scan_images/how_to_scan_images.html#the-efficient-wayor using cv::Mat::at(), for example.

如果你使用C++,使用opencv的C++接口,然后你可以通过http://docs.opencv.org/2.4/doc/tutorials/core/how_to_scan_images/how_to_scan_images.html#the-efficient-way或使用访问成员例如,cv::Mat::at()。

回答by Dat Chu

cv::Matis preferred over IplImagebecause it simplifies your code

cv::Mat首选,IplImage因为它简化了您的代码

cv::Mat img = cv::imread("lenna.png");
for(int i=0; i<img.rows; i++)
    for(int j=0; j<img.cols; j++) 
        // You can now access the pixel value with cv::Vec3b
        std::cout << img.at<cv::Vec3b>(i,j)[0] << " " << img.at<cv::Vec3b>(i,j)[1] << " " << img.at<cv::Vec3b>(i,j)[2] << std::endl;

This assumes that you need to use the RGB values together. If you don't, you can uses cv::split to get each channel separately. See etarion's answer for the link with example.

这假设您需要一起使用 RGB 值。如果不这样做,您可以使用 cv::split 分别获取每个通道。有关示例链接,请参阅 etarion 的回答。

Also, in my cases, you simply need the image in gray-scale. Then, you can load the image in grayscale and access it as an array of uchar.

此外,在我的情况下,您只需要灰度图像。然后,您可以加载灰度图像并将其作为 uchar 数组访问。

cv::Mat img = cv::imread("lenna.png",0);
for(int i=0; i<img.rows; i++)
    for(int j=0; j<img.cols; j++)
        std::cout << img.at<uchar>(i,j) << std::endl;

UPDATE: Using split to get the 3 channels

更新:使用 split 获得 3 个通道

cv::Mat img = cv::imread("lenna.png");
std::vector<cv::Mat> three_channels = cv::split(img);

// Now I can access each channel separately
for(int i=0; i<img.rows; i++)
    for(int j=0; j<img.cols; j++)
        std::cout << three_channels[0].at<uchar>(i,j) << " " << three_channels[1].at<uchar>(i,j) << " " << three_channels[2].at<uchar>(i,j) << std::endl;

// Similarly for the other two channels

UPDATE: Thanks to entarion for spotting the error I introduced when copying and pasting from the cv::Vec3b example.

更新:感谢 entarion 发现了我在从 cv::Vec3b 示例复制和粘贴时引入的错误。

回答by user3188838

Since OpenCV 3.0, there are official and fastest way to run function all over the pixel in cv::Mat.

从 OpenCV 3.0 开始,有官方最快的方法可以在 cv::Mat 中的像素上运行函数。

void cv::Mat::forEach (const Functor& operation)

void cv::Mat::forEach (const Functor& 操作)

If you use this function, operation is runs on multi core automatically.

如果使用此功能,操作将自动在多核上运行。

Disclosure : I'm contributor of this feature.

披露:我是此功能的贡献者。

回答by Martin R.

Since OpenCV 3.3 (see changelog) it is also possible to use C++11 style for loops:

从 OpenCV 3.3(见变更日志)开始,也可以使用 C++11 风格的循环:

// Example 1
Mat_<Vec3b> img = imread("lena.jpg");
for( auto& pixel: img ) {
    pixel[0] = gamma_lut[pixel[0]];
    pixel[1] = gamma_lut[pixel[1]];
    pixel[2] = gamma_lut[pixel[2]];
}

// Example 2
Mat_<float> img2 = imread("float_image.exr", cv::IMREAD_UNCHANGED);
for(auto& p : img2) p *= 2;

回答by vipers36

The docs show a well written comparison of different ways to iterate over a Mat image here.

文档在此处对迭代 Mat 图像的不同方法进行了很好的比较。

The fastest way is to use C style pointers. Here is the code copied from the docs:

最快的方法是使用 C 风格的指针。这是从文档中复制的代码:

Mat& ScanImageAndReduceC(Mat& I, const uchar* const table)
{
// accept only char type matrices
CV_Assert(I.depth() != sizeof(uchar));

int channels = I.channels();

int nRows = I.rows;
int nCols = I.cols * channels;

if (I.isContinuous())
{
    nCols *= nRows;
    nRows = 1;
}

int i,j;
uchar* p;
for( i = 0; i < nRows; ++i)
{
    p = I.ptr<uchar>(i);
    for ( j = 0; j < nCols; ++j)
    {
        p[j] = table[p[j]];
    }
}
return I;
}

Accessing the elements with the at is quite slow.

使用 at 访问元素非常慢。

Note that if your operation can be performed using a lookup table, the built in function LUT is by far the fastest (also described in the docs).

请注意,如果您的操作可以使用查找表执行,则内置函数 LUT 是迄今为止最快的(也在文档中进行了描述)。

回答by Davood Falahati

This is an old question but needs to get updated since opencv is being actively developed. Recently, OpenCV has introduce parallel_for_ which complies with c++11 lambda functions. Here is the example

这是一个老问题,但需要更新,因为 opencv 正在积极开发中。最近,OpenCV 引入了符合 c++11 lambda 函数的 parallel_for_。这是例子

parallel_for_(Range(0 , img.rows * img.cols), [&](const Range& range){
    for(int r = range.start; r<range.end; r++ )
    {
         int i = r / img.cols;
         int j = r % img.cols;
        img.ptr<uchar>(i)[j] = doSomethingWithPixel(img.at<uchar>(i,j));
    }
});

This is mention-worthy that this method uses the CPU cores in modern computer architectures.

值得一提的是,这种方法使用了现代计算机体系结构中的 CPU 内核。

回答by Acidic9

If you want to modify RGB pixels one by one, the example below will help!

如果你想一一修改RGB像素,下面的例子会有所帮助!

void LoopPixels(cv::Mat &img) {
    // Accept only char type matrices
    CV_Assert(img.depth() == CV_8U);

    // Get the channel count (3 = rgb, 4 = rgba, etc.)
    const int channels = img.channels();
    switch (channels) {
    case 1:
    {
        // Single colour
        cv::MatIterator_<uchar> it, end;
        for (it = img.begin<uchar>(), end = img.end<uchar>(); it != end; ++it)
            *it = 255;
        break;
    }
    case 3:
    {
        // RGB Color
        cv::MatIterator_<cv::Vec3b> it, end;
        for (it = img.begin<cv::Vec3b>(), end = img.end<cv::Vec3b>(); it != end; ++it) {
            uchar &r = (*it)[2];
            uchar &g = (*it)[1];
            uchar &b = (*it)[0];
            // Modify r, g, b values
            // E.g. r = 255; g = 0; b = 0;
        }
        break;
    }
    }
}