【问题标题】:Cycle through pixels with opencv使用opencv循环像素
【发布时间】:2010-12-21 22:49:23
【问题描述】:

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

【问题讨论】:

标签: c++ loops opencv pixel


【解决方案1】:

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;

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

另外,在我的情况下,您只需要灰度图像。然后,您可以加载灰度图像并将其作为 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;

更新:使用 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

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

【讨论】:

  • 您如何获得图像的非整数值?
  • img.at&lt;uchar&gt;(i,j)[0] - 这是行不通的 :) [0] 必须离开
  • 我遇到了这个问题,它解决了我遇到的一个问题,但现在我有一个问题,为什么 ::at 有效?为什么它不能单独与 at 一起使用?喜欢 at(0,0)?
  • 因为 ::at 是没有默认类型名的模板方法?
  • 这是对 OpenCV 初学者最有用的帖子之一。如果它有一些关于如何在同一个垫子上循环的额外信息,就好像它是一个一维矩阵一样,那将是完美的。但我想这不是问题......
【解决方案2】:

自 OpenCV 3.0 起,在 cv::Mat 的所有像素上都有官方和最快的方法来运行函数。

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

如果你使用这个功能,操作会自动在多核上运行。

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

【讨论】:

【解决方案3】:

如果你使用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()来访问成员。

【讨论】:

  • 感谢您的链接!看起来类似于 QImage::scanLine,正是我想要的。
  • 您所链接的页面不再可用。
【解决方案4】:

从 OpenCV 3.3 (see changelog) 开始,也可以使用 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;

【讨论】:

    【解决方案5】:

    这是一个老问题,但由于 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));
        }
    });
    

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

    【讨论】:

      【解决方案6】:

      文档展示了迭代 Mat 图像here 的不同方法的书面比较。

      最快的方法是使用 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;
      }
      

      使用 at 访问元素非常慢。

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

      【讨论】:

        【解决方案7】:

        如果你想一一修改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;
            }
            }
        }
        

        【讨论】:

        • 好点,这就是我要找的。如果您独立处理像素,则不需要行/列!
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-06-06
        • 2020-06-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-09-01
        • 1970-01-01
        相关资源
        最近更新 更多