Opencv中图像的遍历与像素操作

Opencv中图像的遍历与像素操作

OpenCV中表示图像的数据结构是cv::Mat,Mat对象本质上是一个由数值组成的矩阵。矩阵的每一个元素代表一个像素,对于灰度图像,像素是由8位无符号数来表示(0代表黑,255代表白);对于彩色图像,每个像素是一个三元向量,即由三个8位无符号数来表示三个颜色通道(Opencv中顺次为蓝、绿、红)。 
我们先来介绍下cv::Mat类的获取像素的成员函数at(),其函数原型如下:

template<typename _Tp> _Tp& at(int i0, int i1);
//由于Mat可以存放任意数据类型的元素,所以该函数是用模板函数来实现的
//它本身不会进行任何数据类型转换,在调用的过程中需要指明像素的数据类型
//即要与矩阵中的数据类型相匹配。如:
img.at<uchar>(i,j)=255
img.at<cv::Vec3b>(i,j)[0]=255

在OpenCV中一般有四种图像遍历的方式,第一种自然是最平凡的数组遍历啦。为方便起见,以下所有的示例都是In-place变换操作。

1、数组遍历

在这里我们通过操作像素的办法来实现图像的镜像变换,即实现flip(img,img,1)的功能。代码如下:

#include<iostream>
#include<opencv2/core/core.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include<opencv2/highgui/highgui.hpp>

using namespace std;
using namespace cv;

void Flip(Mat &img)
{
    int rows=img.rows;
    int cols=img.cols;
    for(int i=0; i<rows; i++)
    {
        for(int j=0; j<cols/2; j++)
        {
            uchar t;
            if(img.channels()==1)
            {
                t=img.at<uchar>(i,j);
                img.at<uchar>(i,j)=img.at<uchar>(i,cols-1-i);
                img.at<uchar>(i,cols-1-i)=t;
            }
            else if(img.channels()==3)
            {
                for(int k=0; k<3; k++)
                {
                    t=img.at<Vec3b>(i,j)[k];
                    img.at<Vec3b>(i,j)[k]=img.at<Vec3b>(i,cols-1-j)[k];
                    img.at<Vec3b>(i,cols-1-j)[k]=t;
                }
            }
        }
    }
}

int main()
{
    Mat img1=imread("test.jpg");  //将任意一张名为test.jpg的图片放置于工程文件夹test中
    imshow("First",img1);
    if(!img1.data)
    {
        cout<<"error! The image is not built!"<<endl;
        return -1;
    }
    Flip(img1);
    imshow("Second",img1);
    waitKey();
    return 0;
}

效果如下: 

2、指针遍历

OpenCV中cv::Mat类提供了成员函数ptr得到图像任意行的首地址。ptr函数是一个模板函数,其原型为:

template<typename _Tp> _Tp* Mat::ptr(int i=0)

在这里我们通过操作像素的办法来实现图像的水平反转,即实现flip(img,img,0)的功能。代码如下:

#include<iostream>
#include<opencv2/core/core.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include<opencv2/highgui/highgui.hpp>

using namespace std;
using namespace cv;

void Flip(Mat &img)
{
    int rows=img.rows;
    int cols=img.cols*img.channels();
    for(int i=0; i<rows/2; i++)
    {
        uchar *p=img.ptr<uchar>(i);
        uchar *q=img.ptr<uchar>(rows-1-i);
        uchar t;
        for(int j=0; j<cols;j++)
        {
            t=*p;
            *p++=*q;
            *q++=t;
        }
    }
}

int main()
{
    Mat img1=imread("test.jpg");  //将任意一张名为test.jpg的图片放置于工程文件夹test中
    imshow("First",img1);
    if(!img1.data)
    {
        cout<<"error! The image is not built!"<<endl;
        return -1;
    }
    Flip(img1);
    imshow("Second",img1);
    waitKey();
    return 0;
}

效果如下: 

指针遍历图像的过程中,我们可能会受以往遍历矩阵的影响,得到图像首行地址后,想直接通过一个循环去遍历rows*cols*img.channels()的内存,但是考虑到一些多媒体处理芯片在行的长度为是4或8的倍数时,对图像的处理会更加高效,所以OpenCV中对图像的每行会填补一些额外像素(不显示、不保存),将填补后的行的长度称为关键字,成员变量step代表以字节为单位的图像的有效宽度。因此,我们只有在图像的有效宽度等于图像的真实宽度,即没有填补时,进行一重循环遍历。我们可以通过cv::Mat的成员函数isContinuous来判断图像是否对行进行了填充,返回值为真,表示没有对行进行填充,反之填充。此外,我们可以通过cv::Mat的成员变量data得到图像的首地址,等效于上面程序中的一种写法如下:

uchar *p=img.data;    //首行首地址
*p += img.step;       //次行首地址
……

3、迭代器遍历

只要对对C++稍有了解,就知道迭代器是专门用于遍历数据集合的一种非常重要的特殊的类,用其遍历隐藏了在给定集合上元素迭代的具体实现方式。C++的STL为每个容器类型都提供了迭代器,OpenCV同样为cv::Mat提供了与STL迭代器兼容的迭代器。

cv::Mat实例的迭代器可以通过创建一个cv::MatIterator_的实例来得到,由于这是一个模板类,所以在声明时需指定图像像素的数据类型。

cv::MatIterator_<cv::Ver3b> it;

另外可使用定义在Mat_内部的迭代器类型

cv::Mat_<cv::Verc3b>::iterator it;

在这里我们通过操作像素的办法来实现图像中心对称反转。代码如下:

#include<iostream>
#include<opencv2/core/core.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include<opencv2/highgui/highgui.hpp>

using namespace std;
using namespace cv;

void Flip(Mat &img)
{
    uchar t;
    if(img.channels()==1)
    {
        Mat_<uchar>::iterator it=img.begin<uchar>();
        Mat_<uchar>::iterator itend=img.end<uchar>();
        itend--;  //通过end成员函数得到的迭代器已超出集合,所以在这里自减
        for(;it<itend;it++,itend--)
        {
            t=*it;*it=*itend;*itend=t;
        }
    }
    else if(img.channels()==3)
    {
        Mat_<Vec3b>::iterator it=img.begin<Vec3b>();
        Mat_<Vec3b>::iterator itend=img.end<Vec3b>();
        itend--;
        for(;it<itend;it++,itend--)
            for(int k=0; k<3; k++)
            {
                t=(*it)[k];(*it)[k]=(*itend)[k];(*itend)[k]=t;
            }
    }
}

int main()
{
    Mat img1=imread("test.jpg");  //将任意一张名为test.jpg的图片放置于工程文件夹test中
    imshow("First",img1);
    if(!img1.data)
    {
        cout<<"error! The image is not built!"<<endl;
        return -1;
    }
    Flip(img1);
    imshow("Second",img1);
    waitKey();
    return 0;
}

效果如下: 

原文地址:https://www.cnblogs.com/dzw2017/p/8414379.html

时间: 2024-12-26 18:11:25

Opencv中图像的遍历与像素操作的相关文章

OpenCV中图像的结构和区别

在OpenCV中,现在有很多种结构类型可以用来表示图像,它们之间有区别又有联系,现在记录一下它们之间的区别和相似之处,以便后面查看. 其中类型有: 1. Iplimage,2. Mat,3.CvMat, 4.CVArr: 其中: 1. IplImage: 较老版本的图像存储类型,在2.0之前使用: 2. CvArr: 也是较老的一种存储结构,是一种抽象的基类. 3. CvMat: 矩阵结构. 4. Mat:  新版本中使用的,推荐使用,是一个图像容器,基本上讲 Mat 是一个类,由两个数据部分组

OpenCV中图像算术操作与逻辑操作

OpenCV中图像算术操作与逻辑操作 在图像处理中有两类最重要的基础操作分别是图像点操作与块操作,简单点说图像点操作就是图像每个像素点的相关逻辑与几何运算.块操作最常见就是基于卷积算子的各种操作.实现各种不同的功能.今天小编就跟大家一起学习OpenCV中图像点操作相关的函数与应用场景.常见算术运算包括加.减.乘.除,逻辑运算包括与.或.非.异或.准备工作: 选择两张大小一致的图像如下.加载成功以后显示如下: 加法操作结果如下: 减法操作结果如下: 乘法操作结果如下: 除法操作结果如下: 权重加法

用opencv读取图像鼠标点的像素,更正一个Bug

作者:skyseraph 出处:http://www.cnblogs.com/skyseraph/ 以下代码在网上流传很广. 不过,调试运行之后发现,功能是正确的,但是内存很快就耗尽,导致死机.经过查找,加上: cvReleaseImage(&img1);    //释放源图像占用的内存 这一行是我(szliug)加的,否则内存很快就会耗尽,会死机的. 之后运行正常. /*===============================================// 功能:OpenCV Ut

[OpenCV-Python] OpenCV 中图像特征提取与描述 部分 V (一)

部分 V图像特征提取与描述 29 理解图像特征 目标本节我会试着帮你理解什么是图像特征,为什么图像特征很重要,为什么角点很重要等.29.1 解释 我相信你们大多数人都玩过拼图游戏吧.首先你们拿到一张图片的一堆碎片,要做的就是把这些碎片以正确的方式排列起来从而重建这幅图像.问题是,你怎样做到的呢?如果把你做游戏的原理写成计算机程序,那计算机就也会玩拼图游戏了.如果计算机可以玩拼图,我们就可以给计算机一大堆自然图片,然后就可以让计算机把它拼成一张大图了.如果计算机可以自动拼接自然图片,那我们是不是可

[OpenCV-Python] OpenCV 中图像特征提取与描述 部分 V (二)

部分 V图像特征提取与描述 34 角点检测的 FAST 算法 目标 ? 理解 FAST 算法的基础 ? 使用 OpenCV 中的 FAST 算法相关函数进行角点检测原理 我们前面学习了几个特征检测器,它们大多数效果都很好.但是从实时处理的角度来看,这些算法都不够快.一个最好例子就是 SLAM(同步定位与地图构建),移动机器人,它们的计算资源非常有限.为了解决这个问题,Edward_Rosten 和 Tom_Drummond 在 2006 年提出里 FAST 算法.我们下面将会对此算法进行一个简单

OpenCV中图像的读取,显示与保存

图像的读取,显示与保存 相关函数:cv2.imread().cv2.imshow().cv2.imwrite() 1.读入图像: 用cv2.imread()函数来读取图像,cv2.imread(路径,图像颜色空间)(其中颜色空间默认为BGR彩图)     cv2.IMREAD_COLOR:读入一副彩色图像 cv2.IMREAD_GRAYSCALE:以灰度模式读入图像 cv2.IMREAD_UNCHANGED:读入一幅图像,并且包括图像的 alpha 通道 示例代码 import cv2 img

opencv中的一个不常见的操作

今天在做机器学习的一个醒项目时遇到了,一个奇怪的Mat用法,各种查资料后终于被我找到了答案. Mat layerSizes = (Mat_<int>(1, 5) << image_rows*image_cols, 128, 128, 128, class_num); 这里有两点 1.Mat_<int>(1, 5)就等价于Mat(1, 5, CV_32S) 2.Mat_<int>(1, 5) << image_rows*image_cols, 12

学习Opencv 2.4.9(二) ---操作像素

作者:咕唧咕唧liukun321 来自:http://blog.csdn.net/liukun321 本质上说一张图像就是由数值组成的矩阵.Opencv 2.x由 cv::Mat 这个数据结构来表示一张图像.矩阵的每一个元素代表了一个像素.对于彩色图像而言矩阵的元素是一个三元数.对图像有了这个新的认识,下面可以试着借助opencv处理图像了. 先来看一下今天要处理的图像: 今天的主题是存取像素,首先来看一下如何存取像素值.其实对于像素值的操作都可以由cv::Mat类中成员直接或间接实现,cv::

OpenCv学习笔记(七)---OpenCv中的基本绘图函数,圆,椭圆,线段,矩形,多边形的绘制(1)

(一)本节教程的目的 本节你将学到: 1--如何使用Point在图像中定义2D点 2--如何以及为何使用Scalar 3--用OpenCv的函数Line绘直线 4--用OpenCvd的函数ellipse绘制椭圆 5--用OpenCv的函数rectangle绘矩形 6--用OpenCv的函数circle绘圆 7--用OpenCv的函数fillPoly绘填充多边形 (二)原理,本节我们将大量使用Point和Scalar这两个结构: **********************************