OpenCV学习笔记(二):存取像素

OpenCV中图像的变量是cv::Mat类型,是一个包含像素数据的矩阵,对于灰度图像素是一个8位无符号数,彩色图像是一个三元数,表示三个颜色通道(OpenCV默认使用BGR的通道顺序)。


存取像素

image.at<uchar>(y,x) = value;
image.at<cv::Vec3b>(y,x)[channel] = value
//image是cv::Mat类的对象
//channel表明颜色通道号

成员函数at(int y,int x)返回相应数据结构的引用,故可以提取像素也可以修改像素,但前提是使用时必须知道图像的数据类型


在实现知道图像数据类型的情况下,可以使用cv::Mat_来精简代码,该类重载了操作符(),允许通过它直接存取矩阵元素。
假设有一个灰度图,用cv::Mat_可以这样写

cv::Mat_<uchar> im2 = image;
im2(100,50) = 0;
Exp1 给图像添加椒盐噪点
void salt(cv::Mat &src,int n)
{
    for(int k=0;k < n;k++)
    {
        int i = qrand()%src.rows;
        int j = qrand()%src.cols;
        if(src.channels() == 1)
            src.at<uchar>(i,j) = 255;
        else if(src.channels() == 3)
        {
            src.at<cv::Vec3b>(i,j)[0] = 255;
            src.at<cv::Vec3b>(i,j)[1] = 255;
            src.at<cv::Vec3b>(i,j)[2] = 255;
        }
    }
}

遍历图像

1.使用指针遍历图像

cv::Mat 提供ptr函数可以获得图像任意行的首地址。ptr函数是一个模板函数,使用前需要知道图像的数据类型

//获取图像第j行的首地址
uchar *data = image.ptr<uchar>(j);

由于图像数据缓存区对应一个W*H的矩阵,每个元素又是由n个uchar构成(n为图像颜色通道数),所以一个宽W,高H的图像数据是一个大小由W*H*n个uchar构成的内存块。

/*遍历图像*/

int r = image.rows; //行数
int c = image.cols*image.channels();  //每行元素个数
uchar *data = NULL;
for(int i=0;i<r;i++)
{
  data = image.ptr<uchar>(i);
  for(int j=0;j<c;j++)
  {
    data[j]....  // 操作像素  
  }
}
2.使用迭代器遍历图像

OpenCV为cv::Mat提供了与STL迭代器兼容的迭代器。

cv::Mat_<cv::Vec3b>::iterator it = image.begin<cv::Vec3b>();    //初始位置迭代器
cv::Mat_<cv::Vec3b>::iterator itend = image.end<cv::Vec3b>();       //终止位置迭代器
for(;it!=itend;++it)
{
  //操作像素
  (*it)[0]...
  (*it)[1]...
  (*it)[2]...
}
Exp2 对图像缩减颜色
/*将RGB空间划分为同等大小的格子,将每个颜色替代为它所在格子的的中心对应的颜色*/

//指针操作
void colorReduce(const cv::Mat &src,cv::Mat &dst,int div=64)
{
    int c = src.cols*src.channels();
    int r = src.rows;
    if(dst.empty())
    {
        dst.create(r,c,src.type());
        dst = src.clone();
    }
    const uchar *dataIn = NULL;
    uchar *dataOut = NULL;
    for(int i=0;i<r;i++)
    {
        dataIn = src.ptr<uchar>(i);
        dataOut = dst.ptr<uchar>(i);
        for(int j=0;j<c;j++)
        {
            dataOut[j] = dataIn[j]/div*div + div/2;
        }
    }
}

//迭代器
void colorReduce(const cv::Mat &src,,int div=64)
{
  cv::Mat_<cv::Vec3b>::iterator it = image.begin<cv::Vec3b>();  
  cv::Mat_<cv::Vec3b>::iterator itend = image.end<cv::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;
  }  
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值