1、图像的表示

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

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

2、Mat类

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

class CV_EXPORTS Mat
{
public:
//一系列函数
...
/* flag 参数中包含许多关于矩阵的信息,如:
-Mat 的标识
-数据是否连续
-深度
-通道数目
*/
int flags;
//矩阵的维数,取值应该大于或等于 2
int dims;
//矩阵的行数和列数,如果矩阵超过 2 维,这两个变量的值都为-1
int rows, cols;
//指向数据的指针
uchar* data;
//指向引用计数的指针
//如果数据是由用户分配的,则为 NULL
int* refcount; //其他成员变量和成员函数
...
};

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

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

重新创建对象:

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

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

typedef Vec<uchar, > Vec2b;
typedef Vec<uchar, > Vec3b;
typedef Vec<uchar, > Vec4b;
typedef Vec<short, > Vec2s;
typedef Vec<short, > Vec3s;
typedef Vec<short, > Vec4s;
typedef Vec<int, > Vec2i;
typedef Vec<int, > Vec3i;
typedef Vec<int, > Vec4i;

typedef Vec<float, > Vec2f;
typedef Vec<float, > Vec3f;
typedef Vec<float, > Vec4f;
typedef Vec<float, > Vec6f;

typedef Vec<double, > Vec2d;
typedef Vec<double, > Vec3d;
typedef Vec<double, > Vec4d;
typedef Vec<double, > Vec6d; Vec3b color; //用 color 变量描述一种 RGB 颜色
color[]=; //B 分量
color[]=; //G 分量
color[]=; //R 分量

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

 Mat grayim(, , CV_8UC1);
Mat colorim(, , CV_8UC3);
//遍历所有像素,并设置像素值
for( int i = ; i < grayim.rows; ++i)
  for( int j = ; j < grayim.cols; ++j )
    grayim.at<uchar>(i,j) = (i+j)%;
//遍历所有像素,并设置像素值
for( int i = ; i < colorim.rows; ++i) {
  for( int j = ; j < colorim.cols; ++j ){
    Vec3b pixel;
    pixel[] = i%; //Blue
    pixel[] = j%; //Green
    pixel[] = ; //Red
    colorim.at<Vec3b>(i,j) = pixel;
  }
}
//显示结果
imshow("grayim", grayim);
imshow("colorim", colorim);

使用迭代器操作矩阵:

 Mat grayim(, , CV_8UC1);
Mat colorim(, , CV_8UC3);
//遍历所有像素,并设置像素值
MatIterator_<uchar> grayit, grayend;
for( grayit = grayim.begin<uchar>(), grayend =
grayim.end<uchar>(); grayit != grayend; ++grayit)
*grayit = rand()%;
//遍历所有像素,并设置像素值
MatIterator_<Vec3b> colorit, colorend;
for( colorit = colorim.begin<Vec3b>(), colorend =
colorim.end<Vec3b>(); colorit != colorend; ++colorit)
{
(*colorit)[] = rand()%; //Blue
(*colorit)[] = rand()%; //Green
(*colorit)[] = rand()%; //Red
}
//显示结果
imshow("grayim", grayim);
imshow("colorim", colorim);
waitKey();

使用数据指针操作数据:

 // 高效,但是不进行类型以及越界检查
Mat grayim(, , CV_8UC1);
Mat colorim(, , CV_8UC3);
//遍历所有像素,并设置像素值
for( int i = ; i < grayim.rows; ++i)
{
//获取第 i 行首像素指针
uchar * p = grayim.ptr<uchar>(i);
//对第 i 行的每个像素(byte)操作
for( int j = ; j < grayim.cols; ++j )
p[j] = (i+j)%;
}
//遍历所有像素,并设置像素值
for( int i = ; i < colorim.rows; ++i)
{
//获取第 i 行首像素指针
Vec3b * p = colorim.ptr<Vec3b>(i);
for( int j = ; j < colorim.cols; ++j )
{
p[j][] = i%; //Blue
p[j][] = j%; //Green
p[j][] = ; //Red
} }
//显示结果
imshow("grayim", grayim);
imshow("colorim", colorim);
waitKey();

选取图像局部区域

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

1、单行或单列选取

Mat Mat::row(int i) const
Mat Mat::col(int j) const Mat line = A.row(i);

2、多行或多列选择

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

class Range
{
public:
...
int start, end;
};

//创建一个单位阵
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)

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

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

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

4、取对角线元素

Mat Mat::diag(int d) const

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

5、Mat表达式

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

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

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

Mat imread(const string& filename, int flags= )

、flag>,该函数返回  通道图像
、flag=,该函数返回单通道图像
、flag<,则函数不对图像进行通道转换。

7、写图像文件

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

8、读写图片案例

//读入图像,并将之转为单通道图像
Mat im = imread("lena.jpg", );
//请一定检查是否成功读图
if( im.empty() )
{
cout << "Can not load image." << endl;
return -;
}
//进行 Canny 操作,并将结果存于 result
Mat result;
Canny(im, result, , );
//保存结果
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;

//定义视频的宽度和高度
Size s(, );
//创建 writer,并指定 FOURCC 及 FPS 等参数
VideoWriter writer = VideoWriter("myvideo.avi",
CV_FOURCC('M','J','P','G'), , s);
//检查是否成功创建
if(!writer.isOpened())
{
cerr << "Can not create video file.\n" << endl;
return -;
}
//视频帧
Mat frame(s, CV_8UC3);
for(int i = ; i < ; i++)
{
//将图像置为黑色
frame = Scalar::all();
//将整数 i 转为 i 字符串类型
char text[];
snprintf(text, sizeof(text), "%d", i);
//将数字绘到画面上
putText(frame, text, Point(s.width/, s.height/),
FONT_HERSHEY_SCRIPT_SIMPLEX, ,
Scalar(,,), , );
//将图像写入视频
writer << frame;
}
//退出程序时会自动关闭视频文件
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. Test Scenarios for Excel Export functionality

    1 File should get exported in proper file extension2 File name for the exported excel file should be ...

  2. Delphi中的构造函数的override的问题

    TObject的构造方法Create不能被override.因为它是一个静态方法.

  3. 面向对象基础及UML建模语言

    1.面向对象的方法起源于面向对象程序设计语言,其发展过程大体经历了初始阶段.发展阶段和成熟阶段. 2.面向对象方法主要优点 (1)从认识论的角度可以看出,面向对象方法改变了开发软件的方式. (2)面向 ...

  4. MD5 SHA1 CRC32

    md5: import hashlib md5 = hashlib.md5() md5.update(bytes('http://www.baidu.com',encoding="utf-8 ...

  5. 搭建gulp脚手架

    前段时间刚好在开发公司的首页,使用的是gulp工作流,gulp相对于webpack而言,配置简单,也更加直观(很符合直觉),日常开发一些静态页面.html5专题也足够,这里把遇到的坑与实践经验记录一下 ...

  6. 压缩和解压缩文件tar, tar.gz and tar.bz2

    1, 对于tar.gz 压缩:tar -zcvf archive-name.tar.gz directory-name 解压:tar -zxvf prog-1-jan-2005.tar.gz -C / ...

  7. NOIP2018普及组模拟赛

    向老师给的模拟赛,还没普及组难... 题目在洛谷团队里. 第一试三道水题,我46分钟就打完了,然后就AK了. 第二试一看,除了第二题要思考一段时间之外,还是比较水的,但是我得了Rank倒1,115分. ...

  8. P3747 相逢是问候 欧拉定理+线段树

    巨难!!! 去年六省联考唯一的一道黑牌题,我今天一天从早到晚,把它从暴力15分怼到了90分,极端接近正解了. bzoj上A了,但是洛谷和loj上面就不行.伪正解会T,奇奇怪怪的类正解会WA.. 那么, ...

  9. 字符串格式化(七)-format

    print("i am %s" %'admin') # i am admin msg = "i am %s" %'Alex' print(msg) # i am ...

  10. 基于tcp和多线程的多人聊天室-C语言

    之前在学习关于网络tcp和多线程的编程,学了知识以后不用一下总绝对心虚,于是就编写了一个基于tcp和多线程的多人聊天室. 具体的实现过程: 服务器端:绑定socket对象->设置监听数-> ...