opencv图像处理学习(五十八)——遍历处理

1.at下标

2.指针遍历Mat::Ptr<type>

Mat类提供了一个函数模板Mat::Ptr方法,它可用于表示遍历图像的每一个字节,参数可设置为以0为起始行号,默认返回值为uchar*或者const unchar*.Opencv中也提供了相应的模板template<typename_Tp>_Tp* Mat::ptr(int i0 = 0),i0代表的是以零行为基础的索引,函数返回指向特定矩阵行的uchar*或指针。

cv::Mat inverseColor3(cv::Mat srcImage)
{
    cv::Mat tempImage = srcImage.clone();
    int rows = tempImage.rows;
    //将3通道转换为单通道
    int nStep = tempImage.cols * tempImage.channels();
    for(int i =0;i<rows;i++)
    {
        const uchar* pSrcData = srcImage.ptr<uchar>(i);
        uchar* pResultData = srcImage.ptr<uchar>(i);
        for(int j =0;j<nStep;j++)
        {
            pResultData[j]=cv::saturate_cast<uchar>(255-pSrcData[j]);
        }
    }

    return tempImage;
}

cv::saturate_cast<typename>是一个typename类型转换函数,函数功能是确保运算结果在相应的typename类型范围内,其可以解释为强制类型转换,保证像素值变化在[0,255],如果是浮点数,则用round取整。

3.使用迭代器Matlterator_

Matlterator_是Mat数据操作的迭代器。template<typename_Tp>Matlterator_<_Tp>Mat::begin()表示指向Mat数据的起始迭代器,template<typename_Tp>Matlterator_<_Tp>Mat::end()表示指向Mat数据的终止迭代器。迭代器方法是一种更安全的用来来遍历图像像素方式,首先获取到数据图像的矩阵起始,再通过递增迭代实现移动数据指针。

cv::Mat inverseColor4(cv::Mat srcImage)
{
    cv::Mat tempImage = srcImage.clone();
    cv::MatConstIterator_<cv::Vec3b>  srcIterStart = srcImage.begin<cv::Vec3b>;
    cv::MatConstIterator_<cv::Vec3b>  srcIterEnd = srcImage.begin<cv::Vec3b>;
    cv::MatIterator_<cv::Vec3b> resIterStart = tempImage.begin<cv::Vec3b>();
    cv::MatIterator_<cv::Vec3b> resIterEnd = tempImage.end<cv::Vec3b>();

    //遍历图像反色处理
    while(srcIterStart!=srcIterEnd)
    {
        (*resIterStart)[0] = 255 - (*srcIterStart)[0];
        (*resIterStart)[1] = 255 - (*srcIterStart)[1];
        (*resIterStart)[2] = 255 - (*srcIterStart)[2];

        // 迭代器递增
        srcIterStart++;
        resIterStart++;
    }
    return tempImage;
}

4.改进方法isContinous

图像数据存储行与行之间可能是空白单元,即图像行与行之间存储可能是不连续的,因此我们在使用上述方法进行图像像素遍历时,很大程度上会造成数据指针移动的浪费,Mat类提供了一个检测图像是否连续的函数isContinuous(),该函数返回值为true时表示ux元素存储是连续的,每一行直径无间隙,显然1x1和1xN的图像矩阵总是连续的,Mat::creat()方法创建的矩阵也是连续的。当图像元素连续时,我们可以将图像看成一行,按行展开,利用行指针获取起始行位置,进行遍历。

cv::Mat inverseColor5(cv::Mat srcImage)
{
    int rows = srcImage.rows;
    int cols = srcImage.cols;
    cv::Mat tempImage = srcImage.clone();
    
    //    判断是否是连续图像,即是否有像素填充
    if(srcImage.isContinuous() && tempImage.isContinuous())
    {
        rows = 1;
        cols = cols * srcImage.rows * srcImage.channel();//按照行展开

    }

    for(int i = 0;i<rows;i++)
    {
       const uchar* pSrcData = srcImage.ptr<uchar>(i);
       uchar* pResultData = tempImage.ptr<uchar>(i);
       for(int j =0;j<cols;j++)
       {
        *pResultData++ = 255 - *pResultData++;
       } 
    }

    return tempImage;
}

Mat类中提供了Mat.step()方法,用于获取图像一行像素元素的个数。

5.LUT查表法

为了减少图像映射的时间复杂度,Opnecv提供了查找表LUT,LUT是一张像素灰度值的映射表,可用于将采样到的灰度值经过图像处理(替换、反转、赋值、阈值、二值化、灰度变换等),利用映射关系变换成相对应的灰度值。Opencv中LUT查找表包含256个元素,应用于单通道或相同类型的多通道数据操作。

cv::Mat inverseColor6(cv::Mat srcImage)
{
    int rows = srcImage.rows;
    int cols = srcImage.cols
    cv::Mat tempImage= srcImage.clone();
    uchar LUTTable[256];
    for(int i=0;i<256;++i)
    {
        LUTTable[i] = 255 - i;
    }
    cv::Mat LookUpTable(1,256,cv_8U);
    uchar* pData = lookUpTable.data;
    for(int i=0;i<256;++i)
    {
      pData[i] = LUTTable[i];   
    }
    cv::LUT(srcImage,lookUpTable,tempImage);
    return tempImage;
}

LUT方法通过映射关系表大大减少了相关操作的时间复杂度,可广泛应用于图像元素的相关操作。

OpenCV中提供了专门的计时函数getTickCount与getTickFrequency,针对测试代码的时间统计,利用多次测量来取平均值。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值