图像的表示: 矩阵
灰度矩阵 <br>
彩色 (多通道) 如 RGB 图像, RGB 图像的通道顺序是 BGR
- Mat
- class CV_EXPORTS Mat
- {
- public:
- // 一系列函数
- ...
- /* flag 参数中包含许多关于矩阵的信息, 如:
- -Mat 的标识
- - 数据是否连续
- - 深度
- - 通道数目
- */
- int flags;
- // 矩阵的维数, 取值应该大于或等于 2
- int dims;
- // 矩阵的行数和列数, 如果矩阵超过 2 维, 这两个变量的值都为 - 1
- int rows, cols;
- // 指向数据的指针
- uchar* data;
- // 指向引用计数的指针
- // 如果数据是由用户分配的, 则为 NULL
- int* refcount;
- 24
- // 其他成员变量和成员函数
- ...
- };
创建 Mat 对象(构造方法):
- Mat M(3,2,CV_8UC3,Scalar(0,0,255));
- // 创建一个行数为 3, 列数为 2 的图像, 图像元素是 8 位无符号整数, 3 个通道, 初始值为 0,0,255, 为全红
Mat 对象的 type 是: CV_8UC1,CV_16SC1,,CV_64FC4 等
create()方法
at()方法: 读矩阵中某个像素, 或对某个元素赋值
- uchar value = grayim.at<uchar>(i,j);// 读出第 i 行第 j 列像素值
- grayim.at<uchar>(i,j)=128; // 将第 i 行第 j 列像素值设置为 128
迭代器使用 MatIterator
- ```
- include
- include
- using namespace std;
- using namespace cv;
- int main() {
- Mat g(600, 800, CV_8UC1);
- Mat c(600, 800,CV_8UC3);
- MatIterator_
- }
6. 选取图像局部区域: 是浅复制, 注意复制前后共享内存区域 < br>
i. 单行列选取
- row()/col()<br>
- ```
- Mat Mat::row(int i) const
- Mat Mat::col(int j) const
- ```
ii. 多行多列 < br>
Range 类:<br>
- ```
- class Range
- {
- public:
- int start, end; // 从 start 行 (列) 到 end 行(列), 左闭右开
- static .. all(); //all 方法, 静态方法, 表示所有的行列
- };
- ```
如:
- ```
- Mat A = Mat::eye(10,10,CV_32S);
- // 提取第一列到第三列
- Mat B = A(Range::all(),Range(1,3));
- // 提取第一行到第三行
- Mat C = A(Range(1,3),Range::all());
- ```
7. Mat_类: Mat 类的封装:<br>
使用 Mat_类, 那么就可以在变量声明时确定元素的类型, 访问元素时不再需要指定元素类型, 即使得代码简洁
- ### 图像读写: 读写图像文件:<br>
- 1. imread
- Mat imread(const string& filename, int flags=1 );
imread()函数返回的是 Mat 对象.
如果读取文件失败, 则会返回一个空矩阵, 即 Mat::data 的值是 NULL 执行 imread()之后, 需要检查文件是否成功读入, 可以使用 Mat::empty()函数进行检查
flag 参数值有三种情况:
? flag>0, 该函数返回 3 通道图像, 如果磁盘上的图像文件是单通道的灰度图像, 则会被强制转为 3 通道;
? flag=0, 该函数返回单通道图像, 如果磁盘的图像文件是多通道图像, 则会被强制转为单通道;
? flag<0, 则函数不对图像进行通道转换
- 2. imwrite
- bool imwrite(const string& filename, InputArray image,const vector<int>& params=vector<int>())
3. 读入一副图像, 然后对图像进行 Canny 边缘操作:
- #include<iostream>
- #include<opencv2\opencv.hpp>
- using namespace std;
- using namespace cv;
- int main() {
- Mat im = imread("C:\\Users\\duye\\Desktop\\2.jpg",1);
- if (im.empty()) {
- cout <<"Can not load image!" << endl;
- return -1;
- }
- Mat result;
- Canny(im, result, 50, 100);
- imwrite("C:\\Users\\duye\\Desktop\\1.jpg",result);
- return 0;
- }
- ### 视频操作:
1. 读视频:
VideoCapture 既可以从视频文件读取图像, 也可以从摄像头读取图像 < br>
从文件 / 视频读视频:
- #include <iostream>
- #include "opencv2/opencv.hpp"
- using namespace std;
- using namespace cv;
- int main(int argc, char** argv)
- {
- // 打开视频文件
- VideoCapture cap("video.short.raw.avi");
- // 根据摄像头 ip 获取实时视频流
- // 注意这里不再使用定义了的返回的视频流, 直接使用摄像头 ip 就好
- //String videoUrl = "...";
- //VideoCapture cap;
- //cap.open(videoUrl);
- // 检查是否成功打开
- 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;
- }
2. 写视频 < br>
读取摄像头视频, 写入文件中保存
- #include <opencv2/core/core.hpp>
- #include <opencv2/highgui/highgui.hpp>
- using namespace cv;
- void main()
- {
- String url = "http://192.168.1.1:8080";
- VideoCapture cap();
- cap.open(url);
- double rate = 25.0;// 视频的帧率
- Size videoSize(1280,960);
- VideoWriter writer("VideoTest.avi", CV_FOURCC(M, J, P, G), rate, videoSize);
- Mat frame;
- while (capture.isOpened())
- {
- capture>> frame;
- writer << frame;
- imshow("video", frame);
- if (waitKey(20) == 27)//27 是键盘摁下 esc 时, 计算机接收到的 ascii 码值
- {
- break;
- }
- }
- }
- ```
后续我会给出目前比较流行的使用 opencv 实现人脸识别的具体实现以上
来源: http://www.bubuko.com/infodetail-2537470.html