OpenCV 访问图像中的像素|颜色空间缩减

在OpenCV中,提供了三种访问每个像素的方法。

  • 方法一指针访问:C操作符[];
  • 方法二迭代器iterator;
  • 方法三动态地址计算。
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>

using namespace cv;
using namespace std;


/*指针访问:C 操作符[]*/
void colorReduce1(Mat& inputImage, Mat& outputImage, int div)
{
    outputImage = inputImage.clone();
    int rowNumber = outputImage.rows; // 行数
    int colNumber = outputImage.cols * outputImage.channels(); // 列数 x 通道数 = 每一行元素个数

    // 双循环遍历所有像素
    for (int i = 0; i < rowNumber; i++) {
        uchar* data = outputImage.ptr<uchar>(i); // 获取 i 行首地址

        // 列循环
        for (int j = 0; j < colNumber; j++) {
            data[j] = (data[j] / div) * div + div / 2;
            // 也可以
            //*data++ = (*data / div) * div + div / 2;
        }
    }
}

/*用迭代器操作像素*/
void colorReduce2(Mat& inputImage, Mat& outputImage, int div)
{
    outputImage = inputImage.clone();

    // 获取迭代器
    Mat_<Vec3b>::iterator it = outputImage.begin<Vec3b>(); //初始位置迭代器
    Mat_<Vec3b>::iterator itend = outputImage.end<Vec3b>(); // 终止位置迭代器

    for (; it != itend; it++) {
        // 处理开始
        (*it)[0] = ((*it)[0] / div) * div + div / 2;
        (*it)[1] = ((*it)[1] / div) * div + div / 2;
        (*it)[2] = ((*it)[2] / div) * div + div / 2;
        // 处理结束
    }
}

/*动态地址计算*/
void colorReduce3(Mat& inputImage, Mat& outputImage, int div)
{
    outputImage = inputImage.clone(); // 复制实参到临时变量
    int rowNumber = outputImage.rows;
    int colNumber = outputImage.cols;

    for (int i = 0; i < rowNumber; i++) {
        for (int j = 0; j < rowNumber; j++) {
            // 处理开始
            // 蓝色通道
            outputImage.at<Vec3b>(i, j)[0] = (outputImage.at<Vec3b>(i, j)[0] / div) * div + div / 2;
            // 绿色通道
            outputImage.at<Vec3b>(i, j)[1] = (outputImage.at<Vec3b>(i, j)[1] / div) * div + div / 2;
            // 红色通道
            outputImage.at<Vec3b>(i, j)[2] = (outputImage.at<Vec3b>(i, j)[2] / div) * div + div / 2;
            // 处理结束
        }
    }
}


int main(int argc, char ** argv)
{
    Mat srcImage = imread(".//image5.1//1.jpg");
    imshow("原图", srcImage);

    Mat dstImage1;
    Mat dstImage2;
    Mat dstImage3;
    dstImage1.create(srcImage.rows, srcImage.cols, srcImage.type()); // 效果图的大小与原始图的大小类型相同
    dstImage2.create(srcImage.rows, srcImage.cols, srcImage.type()); // 效果图的大小与原始图的大小类型相同
    dstImage3.create(srcImage.rows, srcImage.cols, srcImage.type()); // 效果图的大小与原始图的大小类型相同

    // 记录起始时间
    double time0 = static_cast<double>(getTickCount()); 
    // 调用缩减函数1
    colorReduce1(srcImage, dstImage1, 32);  // 256 / 32 = 8
    time0 = ((double)getTickCount() - time0) / getTickFrequency();
    cout << "指针访问:C操作符[]运行时间为:" << time0 << "秒" << endl;
    imshow("效果图1", dstImage1);   

    time0 = static_cast<double>(getTickCount());

    // 调用缩减函数2
    colorReduce2(srcImage, dstImage2, 32);  // 256 / 32 = 8
    time0 = ((double)getTickCount() - time0) / getTickFrequency();
    cout << "迭代器操作,运行时间为:" << time0 << "秒" << endl;
    imshow("效果图2", dstImage2);

    time0 = static_cast<double>(getTickCount());

    // 调用缩减函数2
    colorReduce3(srcImage, dstImage3, 32);  // 256 / 32 = 8
    time0 = ((double)getTickCount() - time0) / getTickFrequency();
    cout << "动态地址计算,运行时间为:" << time0 << "秒" << endl;
    imshow("效果图3", dstImage3);

    waitKey(0);
    return(0);
}

运行 3 次时间对比:

指针访问:C操作符[]运行时间为:0.002704秒
迭代器操作,运行时间为:0.0986663秒
动态地址计算,运行时间为:0.0809037
指针访问:C操作符[]运行时间为:0.0028266秒
迭代器操作,运行时间为:0.0972075秒
动态地址计算,运行时间为:0.0750282
指针访问:C操作符[]运行时间为:0.0027457秒
迭代器操作,运行时间为:0.0951924秒
动态地址计算,运行时间为:0.0748235

图像输出:




参考:

《OpenCV3 编程入门》 毛星云 P111

posted @   double64  阅读(95)  评论(0编辑  收藏  举报
编辑推荐:
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
点击右上角即可分享
微信分享提示