OpenCV遍历图像像素

引言:

为了构建计算机视觉应用程序,需要学会访问图像内容,有时也要修改或创建图像,如何操作图像的像素,就需要遍历一幅图像并处理每一个像素。现在我们就来介绍OpenCV三种图像像素的遍历方法。

一、 用cv::Mat类的at方法扫描图像

利用cv::Mat的at(int x,int y)方法可以访问元素,其中x是行号,y是列号。在编译时必须明确方法返回值的类型,因为cv::Mat可以接受任何类型的元素,所以程序员需要指定返回值的预期类型。正因为如此,at方法被实现成一个模板方法。在调用at方法时,你必须指定图像元素的类型,例如:

cpp 复制代码
// 单通道图像
image.at<uchar>(i,j)= 255;
// 三通道图像
image.at<cv::Vec3b>(i, j) = cv::Vec3b(255, 255, 255);

用cv::Mat类的at方法扫描图像代码如下:

cpp 复制代码
void visit_mat_by_at(cv::Mat &img)
{
    for (int i = 0; i < img.rows; i++)
    {
        for (int j = 0; j < img.cols; j++)
        {
            // 单通道图像
            if (img.channels() == 1)
            {
                img.at<uchar>(i, j) += 50;
            }
            // 三通道图像
            else
            {
                img.at<cv::Vec3b>(i, j)[0] += 50;
                img.at<cv::Vec3b>(i, j)[1] += 50;
                img.at<cv::Vec3b>(i, j)[2] += 50;
            }
        }
    }
}

二、 用指针扫描图像

一般来说,用指针扫描图像比较高效。在大多数图像处理任务中,执行计算时你都需要对图像的所有像素进行扫描。需要访问的像素数量非常庞大,因此你必须采用高效的方式来执行这个任务。

用指针扫描图像代码如下:

cpp 复制代码
void visit_mat_by_pointer(cv::Mat &img)
{
    for (int i = 0; i < img.rows; i++)
    {
        uchar *data = img.ptr<uchar>(i);
        for (int j = 0; j < img.cols * img.channels(); j++)
        {
            data[j] += 50;
        }
    }
}

三、 用迭代器扫描图像

在面向对象编程时,我们通常用迭代器对数据集合进行循环遍历。迭代器是一种类,专门用于遍历集合的每个元素,并能隐藏遍历过程的具体细节。标准模板库(Standard Template Library,STL)对每个集合类都定义了对应的迭代器类,OpenCV也提供了cv::Mat的迭代器类,并且与C++ STL中的标准迭代器兼容。

用迭代器扫描图像代码如下:

cpp 复制代码
void visit_mat_by_iterator(cv::Mat &img)
{
    // 单通道图像
    if (img.channels() == 1)
    {
        cv::Mat_<uchar>::iterator begin = img.begin<uchar>();
        cv::Mat_<uchar>::iterator end = img.end<uchar>();
 
        for (auto it = begin; it != end; it++)
        {
            *it += 50;
        }
    }
    // 三通道图像
    else
    {
        cv::Mat_<cv::Vec3b>::iterator begin = img.begin<cv::Vec3b>();
        cv::Mat_<cv::Vec3b>::iterator end = img.end<cv::Vec3b>();
 
        for (auto it = begin; it != end; it++)
        {
            (*it)[0] += 50;
            (*it)[1] += 50;
            (*it)[2] += 50;
        }
    }
}

测试代码:

cpp 复制代码
#include <iostream>
#include <opencv2/opencv.hpp>
 
int main()
{
    // 单通道图像
    cv::Mat img1(3, 4, CV_8UC1, 100);
    std::cout << "单通道图像像素修改前:" << std::endl;
    std::cout << img1 << std::endl;
 
    visit_mat_by_at(img1);
    //visit_mat_by_pointer(img1);
    //visit_mat_by_iterator(img1);
    std::cout << "单通道图像像素修改后:" << std::endl;
    std::cout << img1 << std::endl;
 
    // 三通道图像
    cv::Mat img2(3, 4, CV_8UC3, cv::Scalar(100, 150, 200));
    std::cout << "三通道图像像素修改前:" << std::endl;
    std::cout << img2 << std::endl;
 
    visit_mat_by_at(img2);
    //visit_mat_by_pointer(img2);
    //visit_mat_by_iterator(img2);
    std::cout << "三通道图像像素修改后:" << std::endl;
    std::cout << img2 << std::endl;
 
    cv::waitKey();
 
    return 0;
}

运行结果:

bash 复制代码
单通道图像像素修改前:
[100, 100, 100, 100;
 100, 100, 100, 100;
 100, 100, 100, 100]
单通道图像像素修改后:
[150, 150, 150, 150;
 150, 150, 150, 150;
 150, 150, 150, 150]
三通道图像像素修改前:
[100, 150, 200, 100, 150, 200, 100, 150, 200, 100, 150, 200;
 100, 150, 200, 100, 150, 200, 100, 150, 200, 100, 150, 200;
 100, 150, 200, 100, 150, 200, 100, 150, 200, 100, 150, 200]
三通道图像像素修改后:
[150, 200, 250, 150, 200, 250, 150, 200, 250, 150, 200, 250;
 150, 200, 250, 150, 200, 250, 150, 200, 250, 150, 200, 250;
 150, 200, 250, 150, 200, 250, 150, 200, 250, 150, 200, 250]

说明我们完成遍历图像,并成功修改了图像的像素。

相关推荐
黑色叉腰丶大魔王3 小时前
基于 MATLAB 的图像增强技术分享
图像处理·人工智能·计算机视觉
菜狗woc12 小时前
opencv-python的简单练习
人工智能·python·opencv
paixiaoxin14 小时前
CV-OCR经典论文解读|An Empirical Study of Scaling Law for OCR/OCR 缩放定律的实证研究
人工智能·深度学习·机器学习·生成对抗网络·计算机视觉·ocr·.net
西猫雷婶14 小时前
python学opencv|读取图像(十四)BGR图像和HSV图像通道拆分
开发语言·python·opencv
AI视觉网奇14 小时前
人脸生成3d模型 Era3D
人工智能·计算机视觉
云空15 小时前
《QT 5.14.1 搭建 opencv 环境全攻略》
开发语言·qt·opencv
编码小哥15 小时前
opencv中的色彩空间
opencv·计算机视觉
吃个糖糖15 小时前
34 Opencv 自定义角点检测
人工智能·opencv·计算机视觉
禁默15 小时前
2024年图像处理、多媒体技术与机器学习
图像处理·人工智能·microsoft
花花少年15 小时前
【Windows版】opencv 和opencv_contrib配置
opencv·opencv_contrib