• OpenCV遍历图像像素


    引言:

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

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

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

    1. // 单通道图像
    2. image.at(i,j)= 255;
    3. // 三通道图像
    4. image.at(i, j) = cv::Vec3b(255, 255, 255);

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

    1. void visit_mat_by_at(cv::Mat &img)
    2. {
    3. for (int i = 0; i < img.rows; i++)
    4. {
    5. for (int j = 0; j < img.cols; j++)
    6. {
    7. // 单通道图像
    8. if (img.channels() == 1)
    9. {
    10. img.at(i, j) += 50;
    11. }
    12. // 三通道图像
    13. else
    14. {
    15. img.at(i, j)[0] += 50;
    16. img.at(i, j)[1] += 50;
    17. img.at(i, j)[2] += 50;
    18. }
    19. }
    20. }
    21. }

    二、 用指针扫描图像

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

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

    1. void visit_mat_by_pointer(cv::Mat &img)
    2. {
    3. for (int i = 0; i < img.rows; i++)
    4. {
    5. uchar *data = img.ptr(i);
    6. for (int j = 0; j < img.cols * img.channels(); j++)
    7. {
    8. data[j] += 50;
    9. }
    10. }
    11. }

    三、 用迭代器扫描图像

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

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

    1. void visit_mat_by_iterator(cv::Mat &img)
    2. {
    3. // 单通道图像
    4. if (img.channels() == 1)
    5. {
    6. cv::Mat_::iterator begin = img.begin();
    7. cv::Mat_::iterator end = img.end();
    8. for (auto it = begin; it != end; it++)
    9. {
    10. *it += 50;
    11. }
    12. }
    13. // 三通道图像
    14. else
    15. {
    16. cv::Mat_::iterator begin = img.begin();
    17. cv::Mat_::iterator end = img.end();
    18. for (auto it = begin; it != end; it++)
    19. {
    20. (*it)[0] += 50;
    21. (*it)[1] += 50;
    22. (*it)[2] += 50;
    23. }
    24. }
    25. }

    测试代码:

    1. #include
    2. #include
    3. int main()
    4. {
    5. // 单通道图像
    6. cv::Mat img1(3, 4, CV_8UC1, 100);
    7. std::cout << "单通道图像像素修改前:" << std::endl;
    8. std::cout << img1 << std::endl;
    9. visit_mat_by_at(img1);
    10. //visit_mat_by_pointer(img1);
    11. //visit_mat_by_iterator(img1);
    12. std::cout << "单通道图像像素修改后:" << std::endl;
    13. std::cout << img1 << std::endl;
    14. // 三通道图像
    15. cv::Mat img2(3, 4, CV_8UC3, cv::Scalar(100, 150, 200));
    16. std::cout << "三通道图像像素修改前:" << std::endl;
    17. std::cout << img2 << std::endl;
    18. visit_mat_by_at(img2);
    19. //visit_mat_by_pointer(img2);
    20. //visit_mat_by_iterator(img2);
    21. std::cout << "三通道图像像素修改后:" << std::endl;
    22. std::cout << img2 << std::endl;
    23. cv::waitKey();
    24. return 0;
    25. }

    运行结果:

    1. 单通道图像像素修改前:
    2. [100, 100, 100, 100;
    3. 100, 100, 100, 100;
    4. 100, 100, 100, 100]
    5. 单通道图像像素修改后:
    6. [150, 150, 150, 150;
    7. 150, 150, 150, 150;
    8. 150, 150, 150, 150]
    9. 三通道图像像素修改前:
    10. [100, 150, 200, 100, 150, 200, 100, 150, 200, 100, 150, 200;
    11. 100, 150, 200, 100, 150, 200, 100, 150, 200, 100, 150, 200;
    12. 100, 150, 200, 100, 150, 200, 100, 150, 200, 100, 150, 200]
    13. 三通道图像像素修改后:
    14. [150, 200, 250, 150, 200, 250, 150, 200, 250, 150, 200, 250;
    15. 150, 200, 250, 150, 200, 250, 150, 200, 250, 150, 200, 250;
    16. 150, 200, 250, 150, 200, 250, 150, 200, 250, 150, 200, 250]

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

  • 相关阅读:
    Android---RecyclerView替代ListView
    Abnova PSMA磁珠解决方案
    QUIC为什么使用这样的connectionID?
    MYSQL 根据唯一索引键更新死锁问题
    linux学习实操计划0101-linux卸载软件
    2591. 将钱分给最多的儿童(Java)
    latex图片在双栏文档中横跨两栏
    C6678/C6657+ZYNQ/K7/A7 FPGA+AD+北斗的软硬件设计方案
    6- 华为云查看容器日志
    Mybatis-Plus CRUD
  • 原文地址:https://blog.csdn.net/qq_39312146/article/details/134405668