使用opencv循环显示像素

a s*_*ich 26 c++ opencv loops pixel

我怎样才能使用opencv循环一个图像,好像它是一个二维数组来获取每个像素的rgb值?此外,对于此操作,是否优于iplimage?

Dat*_*Chu 44

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;
Run Code Online (Sandbox Code Playgroud)

这假设您需要一起使用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;
Run Code Online (Sandbox Code Playgroud)

更新:使用拆分来获得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
Run Code Online (Sandbox Code Playgroud)

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


use*_*838 13

从OpenCV 3.0开始,在cv :: Mat中运行整个像素的函数有官方和最快的方法.

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

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

披露:我是这个功能的贡献者.

  • 请更新教程 https://docs.opencv.org/3.4/db/da5/tutorial_how_to_scan_images.html 来描述这一点! (2认同)

eta*_*ion 10

如果您使用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().


Dav*_*ati 9

这是一个老问题,但需要更新,因为 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));
    }
});
Run Code Online (Sandbox Code Playgroud)

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


Mar*_* R. 6

从 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;
Run Code Online (Sandbox Code Playgroud)