初识OpenCV
文章目录
初识OpenCV
定义
OpenCV (Open Source Computer Vision Library: http://opencv.org)
开源计算机视觉库
接口
- 2.x 、3.x -> C++
- 1.x -> c
模块化的架构
- core
- imgproc
- video
- calib3d
- features2d
- objdetect
- highgui
- videoio
- gpu
- 。。。
API说明
1、cv Namespace 命名空间
#include "opencv2/core.hpp"
using namespace cv;
当函数名冲突时 强制指定
cv::log(a, a);
a /= std::log(2.);
2、自动内存管理
//引用计数机制实现
// create a big 8Mb matrix
Mat A(1000, 1000, CV_64F);
// create another header for the same matrix;
// this is an instant operation, regardless of the matrix size.
Mat B = A; //B引用指向A
// create another header for the 3-rd row of A; no data is copied either
Mat C = B.row(3); //C指向A的第三行
// now create a separate copy of the matrix D是独立的一份拷贝 内存上
Mat D = B.clone();
// copy the 5-th row of B to C, that is, copy the 5-th row of A
// to the 3-rd row of A.
B.row(5).copyTo(C); //A的第五行拷贝到第三行
// now let A and D share the data; after that the modified version
// of A is still referenced by B and C.
A = D; //A引用指向D 但是之前的内存A'仍然被B和C引用不能释放!
// now make B an empty matrix (which references no memory buffers),
// but the modified version of A will still be referenced by C,
// despite that C is just a single row of the original A
B.release(); //B释放了对A'的引用 只剩下C对A'的引用
// finally, make a full copy of C. As a result, the big modified
// matrix will be deallocated, since it is not referenced by anyone
C = C.clone(); //C也独立了 没有对A'的引用了 引用计数为0 A'内存被释放!
类似于std::shared_ptr 智能指针
Ptr<T> ptr(new T(...));
Ptr<T> ptr = makePtr<T>(...);
3、输出数据的自动内存分配
g++ opencv_test.cpp -lopencv_core -lopencv_imgproc -lopencv_highgui -g
//@filename: opencv_test.cpp
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
using namespace cv;
int main(int argc, char** argv)
{
VideoCapture cap(0);
if(!cap.isOpened()) return -1;
Mat frame, edges;
namedWindow("edges",1);
for(;;)
{
cap >> frame;
cvtColor(frame, edges, COLOR_BGR2GRAY);//灰度转换
GaussianBlur(edges, edges, Size(7,7), 1.5, 1.5);//高斯滤波
Canny(edges, edges, 0, 30, 3);//边缘提取
imshow("edges", edges);
if(waitKey(30) >= 0) break;
}
return 0;
}
4、Mat类
- cv::Mat
-
type:
CV_8UC1、CV_16SC1、CV64FC4 (16或8…是像素值位数;C后是通道数;前面是类型,U是无符号 S是有符号 F是浮点数 当然64位浮点数就是双精度浮点数double)
- create方法根据指定参数决定是否释放内存重新申请内存创建图像
- Vec类可以表示向量 可以表达矩阵元素
- 迭代器 MatIterator_: MatIterator_ a,b;
- row(n)方法 提取一行
- col(n)方法 提取一列
- Range()类可以提取部分
//提取第 1 到 3 列(不包括 3)
Mat B = A(Range::all(), Range(1, 3));//前面是行 后面是列
- 也可以使用Rect方法指定左上右下坐标选取范围
- Size(w, h)指定宽高
- Mat Mat::diag(int d) const选择对角线元素
参数 d<0 时,表示取主对角线上方的次对角线
参数 d=0 时,表示取主对角线;
参数 d>0 是,表示取主对角线下方的次对角线,
参数 d=1 时,表示取主对角线下方,且紧贴主对角线的元素;
-
支持运算
- 加法,减法,取负: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 类型矩 阵)的对应元素被置为 255;否则置 0。
- 矩阵位逻辑运算: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)
-
Mat_类是对Mat类的封装 便于使用某些方法
Mat M(600, 800, CV_8UC1);
int i=1, j=2;
double d1 = (double) ((i+j)%255); //用 at()读写像素时,需要指定类型
M.at<uchar>(i,j) = d1;
//下面代码错误,应该使用 at<uchar>() //但编译时不会提醒错误
//运行结果不正确,d2 不等于 d1
double d2 = M.at<double>(i,j);
Mat_<uchar> M1 = (Mat_<uchar>&)M
double d3 = (double) ((i+j)%255);
//直接使用Matlab 风格的矩阵元素读写,简洁
M1(i,j) = d3;
double d4 = M1(i,j);
- 矩阵内存
矩阵 = 矩阵头 + 一个指向存储所有像素值的矩阵的指针。
矩阵头(包含矩阵尺寸,存储方法, 存储地址等信息)的尺寸是常数值,但矩阵本身的尺寸会依图像的不同而不同,通常比矩阵头的尺寸大数个数量级。复制矩阵数据往往花费较多时间,因此除非有必要,不要复制大的矩阵
- IplImage 和 CvMat 转换Mat 版本兼容 略
5、数据获取与存储
5.1 图像读写
- imread() 将图像读取到内存
很明显参数 filename 是被读取或者保存的图像文件名;在 imread()函数中,#失败,则Mat::data为NULL, Mat::empty()方法测试 Mat imread(const string& filename, int flags=1 )
flag 参数值有三种情况:- flag>0,该函数返回 3 通道图像,如果磁盘上的图像文件是单通道的灰 度图像,则会被强制转为 3 通道;
- flag=0,该函数返回单通道图像,如果磁盘的图像文件是多通道图像,则 会被强制转为单通道;
- flag<0,则函数不对图像进行通道转换
- imwrite() Mat对象以图像文件格式保存
bool imwrite(const string& filename, InputArray image, const vector<int>& params=vector<int>()
/***
1、推荐使用 PNG 文件格式,无损压缩
2、第三个参数 params 可以指定文件格式的一些细节信息。这
个参数里面的数值是跟文件格式相关的:
JPEG:表示图像的质量,取值范围从 0 到 100。数值越大表示图像质量 越高,当然文件也越大。默认值是 95。
PNG:表示压缩级别,取值范围是从 0 到 9。数值越大表示文件越小, 但是压缩花费的时间也越长。默认值是 3。
PPM,PGM或 PBM:表示文件是以二进制还是纯文本方式存储,取值为 0 或 1。如果取值为 1,则表示以二进制方式存储。默认值是 1
3、并不是所有的Mat 对象都可以存为图像文件,目前支持的格式只有 8U 类型
的单通道和 3 通道(颜色顺序为 BGR)矩阵。其他的可以转换,用 Mat::convertTo()函数或者 cvtColor()函数
4、在保存文件时,如果文件已经存在,imwrite()函数不会 进行提醒,将直接覆盖掉以前的文件
***/
eg. 图片缩放
g++ opencv_test.cpp -lopencv_imgproc -lopencv_highgui -lopencv_core -g
//@filename: opencv_test.cpp
#include<iostream>
#include<opencv2/imgproc/imgproc.hpp>
#include<opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<string>
using namespace std;
using namespace cv;
int main(){
string imgname ="tiger.jpeg";
//读取图片
cv::Mat img =cv::imread(imgname.c_str());
// //缩放成224,244
cout<< img.rows << " , "<< img.cols <<endl;
cout<< "in size " << img.size() << endl;
Size s(224, 224);
Mat dst = Mat::zeros(s, CV_64FC3);//共有224*224个像素点 每个像素点有3个通道 每个通道使用64位进行表示 即每个像素点24字节大小(位深度)
resize(img, dst, dst.size());
cout<< "out size " << dst.size() << endl; //[224 X 224]
cout <<" and area :" << s.area() << endl;//面积 50176
imwrite("test.png", dst);
return 0;
}
5.2 视频读写
OpenCV 2 中提供了两个类来实现视频的读写。读视频的类是 VideoCapture,
写视频的类是 VideoWriter
VideoCapture 既可以从视频文件读取图像,也可以从摄像头读取图像 可以 使用该类的构造函数打开视频文件或者摄像头。如果 VideoCapture 对象已经创 建,也可以使用 VideoCapture::open()打开,VideoCapture::open()函数会自动调用 VideoCapture::release()函数,先释放已经打开的视频,然后再打开新视频
//打开第一个摄像头
VideoCapture cap1(0);
//打开视频文件
VideoCapture cap2("video.short.raw.avi");
//检查是否成功打开
if(!cap.isOpened()) {
exit(-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;
}
需要在创建视频时设置一系列参数,包括:文件名,编解码器,帧率,宽度和高度等。编解码器 使用四个字符表示,可以是 CV_FOURCC(‘M’,‘J’,‘P’,‘G’)、CV_FOURCC(‘X’,‘V’,‘I’,‘D’)及 CV_FOURCC(‘D’,‘I’,‘V’,‘X’)等。
写视频类VideoWriter::write()函数,VideoWriter 类中也重载
了<<操作符
注意:待写入的图像尺寸必须与创建 视频时指定的尺寸一致
//定义视频的宽度和高度
Size s(320, 240);
//创建writer,并指定FOURCC 及 FPS 等参数
VideoWriter writer = VideoWriter("myvideo.avi", CV_FOURCC('M','J','P','G'), 25, s);
if(!writer.isOpened()) exit(-1);
//视频帧
Mat frame(s, CV_8UC3);//尺寸一致
//将图像置为黑色
frame = Scalar::all(0);
char text[128]="I LOVE U";
//绘图
putText(frame,
text,
Point(s.width/3, s.height/3),
FONT_HERSHEY_SCRIPT_SIMPLEX,
3,
Scalar(0,0,255), //BGR 红色!
3,
8);
//将图像写入视频
writer << frame;
参考及进阶资料
- [1] 官网 欢迎来到opencv!
- [2] 于仕琪 opencv入门教程
- [3] woft王 图像处理之高斯滤波
- [4] c语言中文网
- [5] learnopencv
- [6] opencv中文翻译
- [7] python opencv学习
- [8] opencv 油管教程
- [9] opencv笔记博客