1、图像的表示

  在计算机看来,图像只是一些亮度各异的点,一副M*N的图片可以用M*N的矩阵来表示,矩阵的值表示这个位置上像素的亮度。

  一般灰度图用二维矩阵来表示,彩色(多通道)图用三维矩阵表示,大部分设备都是用无符号8位整数(CV_8U)表示像素的亮度。

2、Mat类

OpenCV中使用Mat类(Matrix的简称)来表示图片,能够自动管理内存。

  1. class CV_EXPORTS Mat
  2. {
  3. public:
  4. //一系列函数
  5. ...
  6. /* flag 参数中包含许多关于矩阵的信息,如:
  7. -Mat 的标识
  8. -数据是否连续
  9. -深度
  10. -通道数目
  11. */
  12. int flags;
  13. //矩阵的维数,取值应该大于或等于 2
  14. int dims;
  15. //矩阵的行数和列数,如果矩阵超过 2 维,这两个变量的值都为-1
  16. int rows, cols;
  17. //指向数据的指针
  18. uchar* data;
  19. //指向引用计数的指针
  20. //如果数据是由用户分配的,则为 NULL
  21. int* refcount;
  22.  
  23. //其他成员变量和成员函数
  24. ...
  25. };

使用构造函数来创建Mat对象:

  1. Mat M(,, CV_8UC3, Scalar(,,));
    // 创建一个行数为3,列数为2的图像,像素元素是8位无符号整型,初始化为0,0,255(默认颜色顺序为BGR)
  2. cout << "M = " << endl << " " << M << endl;

重新创建对象:

  1. Mat M(,, CV_8UC3);//构造函数创建图像
  2. M.create(,, CV_8UC2);//释放内存重新创建图像,但无法设置像素的初始值

矩阵基本元素表达的话,单通道一般用8U,当然也可以是16S、32F等,这些数据类型可以直接用uchar/short/float等基本数据类型表达。但遇到多通道图形,如RGB彩色图像的时候,依然将图形视为一个二维矩阵,但矩阵的元素不再是基本数据类型,而是使用OpenVC中的模板类Vec表示:

  1. typedef Vec<uchar, > Vec2b;
  2. typedef Vec<uchar, > Vec3b;
  3. typedef Vec<uchar, > Vec4b;
  4. typedef Vec<short, > Vec2s;
  5. typedef Vec<short, > Vec3s;
  6. typedef Vec<short, > Vec4s;
  7. typedef Vec<int, > Vec2i;
  8. typedef Vec<int, > Vec3i;
  9. typedef Vec<int, > Vec4i;

  10. typedef Vec<float, > Vec2f;
  11. typedef Vec<float, > Vec3f;
  12. typedef Vec<float, > Vec4f;
  13. typedef Vec<float, > Vec6f;

  14. typedef Vec<double, > Vec2d;
  15. typedef Vec<double, > Vec3d;
  16. typedef Vec<double, > Vec4d;
  17. typedef Vec<double, > Vec6d;
  18.  
  19. Vec3b color; //用 color 变量描述一种 RGB 颜色
  20. color[]=; //B 分量
  21. color[]=; //G 分量
  22. color[]=; //R 分量

使用at()函数操作矩阵:

  1. Mat grayim(, , CV_8UC1);
  2. Mat colorim(, , CV_8UC3);
  3. //遍历所有像素,并设置像素值
  4. for( int i = ; i < grayim.rows; ++i)
  5.   for( int j = ; j < grayim.cols; ++j )
  6.     grayim.at<uchar>(i,j) = (i+j)%;
  7. //遍历所有像素,并设置像素值
  8. for( int i = ; i < colorim.rows; ++i) {
  9.   for( int j = ; j < colorim.cols; ++j ){
  10.     Vec3b pixel;
  11.     pixel[] = i%; //Blue
  12.     pixel[] = j%; //Green
  13.     pixel[] = ; //Red
  14.     colorim.at<Vec3b>(i,j) = pixel;
  15.   }
    }
  16. //显示结果
  17. imshow("grayim", grayim);
  18. imshow("colorim", colorim);

使用迭代器操作矩阵:

  1. Mat grayim(, , CV_8UC1);
  2. Mat colorim(, , CV_8UC3);
  3. //遍历所有像素,并设置像素值
  4. MatIterator_<uchar> grayit, grayend;
  5. for( grayit = grayim.begin<uchar>(), grayend =
  6. grayim.end<uchar>(); grayit != grayend; ++grayit)
  7. *grayit = rand()%;
  8. //遍历所有像素,并设置像素值
  9. MatIterator_<Vec3b> colorit, colorend;
  10. for( colorit = colorim.begin<Vec3b>(), colorend =
  11. colorim.end<Vec3b>(); colorit != colorend; ++colorit)
  12. {
  13. (*colorit)[] = rand()%; //Blue
  14. (*colorit)[] = rand()%; //Green
  15. (*colorit)[] = rand()%; //Red
  16. }
  17. //显示结果
  18. imshow("grayim", grayim);
  19. imshow("colorim", colorim);
  20. waitKey();

使用数据指针操作数据:

  1. // 高效,但是不进行类型以及越界检查
    Mat grayim(, , CV_8UC1);
  2. Mat colorim(, , CV_8UC3);
  3. //遍历所有像素,并设置像素值
  4. for( int i = ; i < grayim.rows; ++i)
  5. {
  6. //获取第 i 行首像素指针
  7. uchar * p = grayim.ptr<uchar>(i);
  8. //对第 i 行的每个像素(byte)操作
  9. for( int j = ; j < grayim.cols; ++j )
  10. p[j] = (i+j)%;
  11. }
  12. //遍历所有像素,并设置像素值
  13. for( int i = ; i < colorim.rows; ++i)
  14. {
  15. //获取第 i 行首像素指针
  16. Vec3b * p = colorim.ptr<Vec3b>(i);
  17. for( int j = ; j < colorim.cols; ++j )
  18. {
  19. p[j][] = i%; //Blue
  20. p[j][] = j%; //Green
  21. p[j][] = ; //Red
  22. }
  23.  
  24. }
  25. //显示结果
  26. imshow("grayim", grayim);
  27. imshow("colorim", colorim);
  28. waitKey();

选取图像局部区域

Mat类提供了多钟方便的方法来选择图像局部区域,但这些方法并不进行内存复制操作。如果将图像局部区域赋值给新的Mat对象,新对象和原始对象将共用相同的数据区域。因为不申请内存,所以执行速度都比较快。

1、单行或单列选取

  1. Mat Mat::row(int i) const
  2. Mat Mat::col(int j) const
  3.  
  4. Mat line = A.row(i);

2、多行或多列选择

Range是OpenVC中新增的类,该类有两个关键变量start和end,可以用来表示矩阵的多个连续的行或者列。其表示的范围为从start到end,包含start但不包含end

  1. class Range
  2. {
  3. public:
  4. ...
  5. int start, end;
  6. };

//创建一个单位阵
Mat A = Mat::eye(10, 10, CV_32S);
//提取第 1 到 3 列(不包括 3)
Mat B = A(Range::all(), Range(1, 3));
//提取 B 的第 5 至 9 行(不包括 9)
//其实等价于 C = A(Range(5, 9), Range(1, 3))
Mat C = B(Range(5, 9), Range::all());

3、感兴趣的区域(Region of interest)

从图像中可以提取感兴趣的区域,有两种方法

  1. //创建宽度为 320,高度为 240 的 3 通道图像
  2. Mat img(Size(,),CV_8UC3);
  3. //roi 是表示 img 中 Rect(10,10,100,100)区域的对象
  4. Mat roi(img, Rect(,,,));
  5. 除了使用构造函数,还可以使用括号运算符,如下:
  6. Mat roi2 = img(Rect(,,,));
  7. 当然也可以使用 Range 对象来定义感兴趣区域,如下:
  8. //使用括号运算符
  9. Mat roi3 = img(Range(,),Range(,));

 //使用构造函数
  Mat roi4(img, Range(10,100),Range(10,100));

4、取对角线元素

  1. Mat Mat::diag(int d) const

参数 d=0 时,表示取主对角线;当参数 d>0 是,表示取主对角线下方的次对
角线,如 d=1 时,表示取主对角线下方,且紧贴主多角线的元素;当参数 d<0 时,
表示取主对角线上方的次对角线。

5、Mat表达式

利用C++运算符重载,代码变的更简洁易懂

  1. 下面给出 Mat 表达式所支持的运算。下面的列表中使用 A B 表示 Mat
  2. 型的对象,使用 s 表示 Scalar 对象,alpha 表示 double 值。
  3. 加法,减法,取负:A+BA-BA+sA-ss+As-A,-A
  4. 缩放取值范围:A*alpha
  5. 矩阵对应元素的乘法和除法: A.mul(B),A/Balpha/A
  6. 矩阵乘法:A*B (注意此处是矩阵乘法,而不是矩阵对应元素相乘)
  7. 矩阵转置:A.t()
  8. 矩阵求逆和求伪逆:A.inv()
  9. 矩阵比较运算:A cmpop BA cmpop alphaalpha cmpop A。此处 cmpop
  10. 可以是>,>=,==,!=,<=,<。如果条件成立,则结果矩阵(8U 类型矩
  11. 阵)的对应元素被置为 ;否则置
  12. 矩阵位逻辑运算:A logicop BA logicop ss logicop A,~A,此处 logicop
  13. 可以是&,|和^。
  14.  
  15. 矩阵对应元素的最大值和最小值:min(A, B),min(A, alpha),max(A, B),
  16. max(A, alpha)。
  17. 矩阵中元素的绝对值:abs(A)
  18. 叉积和点积:A.cross(B),A.dot(B)

6、读图像文件(需要安装对应图像格式的文件格式库)

  1. Mat imread(const string& filename, int flags= )
  2.  
  3. flag>,该函数返回 通道图像
  4. flag=,该函数返回单通道图像
  5. flag<,则函数不对图像进行通道转换。

7、写图像文件

  1. bool imwrite(const string& filename, InputArray image,
  2.           const vector<int>& params=vector<int>())
    // params可以指定文件格式的一些信息

8、读写图片案例

  1. //读入图像,并将之转为单通道图像
  2. Mat im = imread("lena.jpg", );
  3. //请一定检查是否成功读图
  4. if( im.empty() )
  5. {
  6. cout << "Can not load image." << endl;
  7. return -;
  8. }
  9. //进行 Canny 操作,并将结果存于 result
  10. Mat result;
  11. Canny(im, result, , );
  12. //保存结果
  13. imwrite("lena-canny.png", result);

9、读写视频

  视频的格式主要是由压缩算法决定,称之为编码器(coder),解压算法称之为解码器(decoder),统称codec。OpenVC使用VideoCapture和VideoWriter来实现视频的读写。

//打开第一个摄像头
//VideoCapture cap(0);
//打开视频文件
VideoCapture cap("video.short.raw.avi");

//检查是否成功打开
if(!cap.isOpened())
{
cerr << "Can not open a camera or file." << endl;
return -1;
}
Mat edges;
//创建窗口
namedWindow("edges",1);
for(;;)
{
Mat frame;
//从 cap 中读一帧,存到 frame
cap >> frame;
//如果未读到图像
if(frame.empty())
break;
//将读到的图像转为灰度图
cvtColor(frame, edges, CV_BGR2GRAY);
//进行边缘提取操作
Canny(edges, edges, 0, 30, 3);
//显示结果
imshow("edges", edges);
//等待 30 秒,如果按键则推出循环
if(waitKey(30) >= 0)
break;
}
//退出时会自动释放 cap 中占用资源
return 0;

  1. //定义视频的宽度和高度
  2. Size s(, );
  3. //创建 writer,并指定 FOURCC 及 FPS 等参数
  4. VideoWriter writer = VideoWriter("myvideo.avi",
  5. CV_FOURCC('M','J','P','G'), , s);
  6. //检查是否成功创建
  7. if(!writer.isOpened())
  8. {
  9. cerr << "Can not create video file.\n" << endl;
  10. return -;
  11. }
  12. //视频帧
  13. Mat frame(s, CV_8UC3);
  14. for(int i = ; i < ; i++)
  15. {
  16. //将图像置为黑色
  17. frame = Scalar::all();
  18. //将整数 i 转为 i 字符串类型
  19. char text[];
  20. snprintf(text, sizeof(text), "%d", i);
  21. //将数字绘到画面上
  22. putText(frame, text, Point(s.width/, s.height/),
  23. FONT_HERSHEY_SCRIPT_SIMPLEX, ,
  24. Scalar(,,), , );
  25. //将图像写入视频
  26. writer << frame;
  27. }
  28. //退出程序时会自动关闭视频文件
  29. return ;

OpenCV入门(1)- 简介的更多相关文章

  1. OpenCV入门学习笔记

    OpenCV入门学习笔记 参照OpenCV中文论坛相关文档(http://www.opencv.org.cn/) 一.简介 OpenCV(Open Source Computer Vision),开源 ...

  2. OpenCV 入门

    1.入门攻略[安装用] https://www.cnblogs.com/linshuhe/p/5764394.html 2.VS2017配置opencv教程(超详细!!!) https://blog. ...

  3. 系列文章 -- OpenCV入门教程

     <OpenCV3编程入门>内容简介&勘误&配套源代码下载 [OpenCV入门教程之十八]OpenCV仿射变换 & SURF特征点描述合辑 [OpenCV入门教程之 ...

  4. [OpenCV入门教程之十二】OpenCV边缘检测:Canny算子,Sobel算子,Laplace算子,Scharr滤波器合辑

    http://blog.csdn.net/poem_qianmo/article/details/25560901 本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接:http://blog ...

  5. GBDT(MART) 迭代决策树入门教程 | 简介

    GBDT(MART) 迭代决策树入门教程 | 简介  http://blog.csdn.net/w28971023/article/details/8240756

  6. 【OpenCV入门教程之一】 安装OpenCV:OpenCV 3.0 +VS 2013 开发环境配置

    图片太多,具体过程参照: [OpenCV入门教程之一] 安装OpenCV:OpenCV 3.0.OpenCV 2.4.8.OpenCV 2.4.9 +VS 开发环境配置 说下我这边的设置: 选择deb ...

  7. 【OpenCV入门指南】第一篇 安装OpenCV

    http://blog.csdn.net/morewindows/article/details/8225783/ win10下vs2015配置Opencv3.1.0过程详解(转) http://ww ...

  8. 【OpenCV入门教程之三】 图像的载入,显示和输出 一站式完全解析(转)

    本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接:http://blog.csdn.net/poem_qianmo/article/details/20537737 作者:毛星云(浅墨)  ...

  9. 【OpenCV入门教程之一】 安装OpenCV:OpenCV 3.0、OpenCV 2.4.8、OpenCV 2.4.9 +VS 开发环境配置

    本系列文章由@浅墨_毛星云 出品,转载请注明出处.   文章链接:http://blog.csdn.net/poem_qianmo/article/details/19809337 作者:毛星云(浅墨 ...

  10. jQuery的入门与简介

    jQuery的入门与简介<思维导图>   <初学者请各位高手指点指点> jQuery是继Prototype之后又一个优秀的JavaScript库,在JavaScript基础上我 ...

随机推荐

  1. SVN上线步骤笔记

    项目代码位置: /data/svn/play_out 项目代码目录名称: test SVN创建位置:/data/svn/repos_Websvn线上地址:svn://192.168.1.1/repos ...

  2. r=a*(1-sinx)

    a=-2*pi:.001:2*pi; %设定角度b=(1-sin(a)); %设定对应角度的半径polar(a, b,'r') %绘图 夏目漱石“今夜月色很好” 王家卫“我已经很久没有坐过摩托车了,也 ...

  3. 如何在Anaconda中实现多版本python共存

    anaconda中Python版本是3.5,因为爬虫原因,需要Python2.7版本,因此,希望能在anaconda中Python3和Python2共存. 1. 打开Anaconda Prompt,可 ...

  4. Django-website 程序案例系列-12 CSRF

    django为用户实现防止跨站请求伪造的功能 需要配置settings.py:  django.middleware.csrf.CsrfViewMiddleware 1. form表单提交 <f ...

  5. BZOJ4946 NOI2017蔬菜(贪心+堆)

    容易想到一个费用流做法:将每种蔬菜拆成p种,对应p个过期时间,每一种向可以卖的时间连边,第一次卖的奖励算在最晚过期的一种里.对于天数动态加点.不过这样边数太多了,因为第i天能卖的第i-1天一定能卖,可 ...

  6. JavaScript实现两小时倒计时

    [构思] 因为只需要的是两小时,所以时间直接写死,然后通过setInterval每1000ms对时间进行减1操作 前期未考虑到当时分秒小于10的状态,所以后面又加上了一个checkTime()来进行限 ...

  7. Uva10474-STL水题-白书

    白书的一道水题.话说好久没认真做难题了.今天出了排名,所有队伍里倒数第一啊! 代码没什么可说的了. #include <algorithm> #include <cstring> ...

  8. CUBA如何新增ServiceBean

    简单的方法 在页面MIDDLEWARE模块,可以直接新建.编辑.删除 复杂的方法 在代码中手动实现,则需要1.添加Serviceweb-spring.xml中,添加 <entry key=&qu ...

  9. luogu2024 食物链 (并查集)

    把一个点拆成三个,分别对应它的同类.它的猎物和它的天敌,这样的话(以下的相等都是并查集意义上的): 如果令a,b同类,那么a的猎物不能是b的同类,a的天敌不能是b的同类 如果令a吃b,那么a的同类不能 ...

  10. 在Android中通过导入静态数据库来提高应用第一次的启动速度

    一个Android应用给用户的第一印象非常重要,除了要有好的创意和美观的界面,性能也是很关键的部分,本文讨论的就是第一次启动的速度问题. Android应用的启动过程不能让用户等待太长时间,个人觉得最 ...