OpenCV Demo——core模块(1)图像读取与显示

OpenCV Demo系列文章将按照opencv2模块core、imgproc、highgui、calib3d、feature2d、video、objdetect、ml、gpu的顺序,记录和分析一些常用的函数、功能及注意事项,后期打算加入一些具体的应用实例。常用的demo将整理到github,欢迎交流与指正。

core模块(1)图像读取与显示

这篇文章将介绍opencv2中读取和显示图像的函数,作为opencv系列的第一篇文章,本文顺带介绍一下opencv2与旧版本opencv的一些区别,下面的demo会给出opencv1和opencv2的两种实现方式。

1、数据类型与函数说明

Mat

存放矩阵或者图像,包括矩阵信息头、矩阵指针。

opencv2引入的C++接口,Mat是一个类,有它的数据和函数成员。

Mat自动分配和释放内存,是opencv1到opencv2的一个巨大改进(opencv1需要手动释放内存)


imread()


读取图像,用法:imread("图像路径")


namedWindow()


创建显示窗口,用于显示图片或者视频,用法:namedWindow("窗口名称")


imshow()


显示图像,用法:imshow("用于显示的窗口名称",图像名称)


waitKey()


等待按键按下,并且返回按键的值。

用法:key=waitKey(delay),等待delay毫秒,期间有键按下则将其返回给key。

若delay为0或者为负,无限等待

2、demo

这个demo实现图像的读取和显示,分为非命令行模式与命令行模式,本质上是一样的,着重了解一下命令行模式。

2.1 非命令行模式

非命令行模式,直接在程序中传参数,而不是在运行的时候再传递参数。
<span style="font-size:18px;">#include<iostream>
#include"opencv2\core\core.hpp"
#include"opencv2\highgui\highgui.hpp"
using namespace cv;
using namespace std;

int main(){
	/*opencv2版本,矩阵结构Mat,函数imread(),nameWindow(),imshow()*/
	Mat img1=imread("D:\\1.jpg");   //注意是双反斜杠,否则读不到图片
	if(!img1.data) {cout<<"error1";return -1;}   //检查有没有读到图片
	namedWindow("图片1");//有两个参数,第二个有默认形参
	imshow("图片1",img1);
	waitKey(10);

	/*opencv老版本,数据结构IplImage,函数cvLoadImage(),cvNamedWindow(),cvShowImage()*/
	IplImage* img2=cvLoadImage("D:\\2.jpg");
	if(!img2)  {cout<<"error2";return -1;} 
	cvNamedWindow("图片2");
	cvShowImage("图片2",img2);
	cvWaitKey(10);
	cvReleaseImage(&img2);
	cvDestroyWindow("图片2");   //老版本opencv需要手动释放内存
	
	return 0;
}</span>


opencv1与opencv2的区别?

观察opencv1版本的函数可以发现,所有函数名都有前缀cv,如cvLoadImage()。而在opencv2中,已经将所有函数和变量名放入命名空间cv,因此,opencv2版本中与opencv兼容的所有函数都无须加前缀cv。

观察opencv2的函数名,可以发现它们遵循驼峰命名准则。也就是第一个字母为小写并且后续单词首字母大写(如 waitKey() ),若是单个单词作为函数名则第一个字母大写,如 Canny()。

2.2 命令行模式

<span style="font-size:18px;">#include<iostream>
#include"opencv2\core\core.hpp"
#include"opencv2\highgui\highgui.hpp"
using namespace cv;
using namespace std;

int main2(int argc,char** argv){
	/*opencv2版本,矩阵结构Mat,函数imread(),nameWindow(),imshow()*/
	Mat img1=imread(argv[1]);   //注意是双反斜杠,否则读不到图片
	if(!img1.data) {cout<<"error1";return -1;}   //检查有没有读到图片
	namedWindow("图片1");//有两个参数,第二个有默认形参
	imshow("图片1",img1);
	waitKey(10);

	/*opencv老版本,数据结构IplImage,函数cvLoadImage(),cvNamedWindow(),cvShowImage()*/
	IplImage* img2=cvLoadImage(argv[2]);
	if(!img2)  {cout<<"error2";return -1;} 
	cvNamedWindow("图片2");
	cvShowImage("图片2",img2);
	cvWaitKey(10);
	cvReleaseImage(&img2);
	cvDestroyWindow("图片2");   //老版本opencv需要手动释放内存

	return 0;
}</span>

什么是命令行程序?
命令行模式程序,是运行在命令行界面的程序,比如windows系统下的dos,linux下的bash都是命令行界面。
看上面的main函数,有两个形参,argc表示后面接的参数个数,argv[0]表示函数本身的地址,argv[1]表示第一个参数,argv[2]表示第二个参数.....以此类推。
比如本程序编译后生成imgRead_Show.exe文件,则可以在命令行模式下运行:

<span style="font-size:18px;">imgRead_Show.exe  D:\\1.jpg  D:\\2.jpg</span>

则传入参数:argc=3,argv[1]="D:\\1.jpg",argv[2]="D:\\2.jpg",与非命令行程序本质是一样的。

在dos中的运行效果图:
OpenCV Demo——core模块(1)图像读取与显示_第1张图片

3、再谈Mat

介绍Mat的特性,特别是Mat的复制构造。前面提到Mat包括信息头以及矩阵指针,矩阵指针指向的就是图片的内存空间,当我们要复制一张图片或者复制一个矩阵的时候,有很多种方法,但是必须注意复制有“浅复制”和“深复制”两种,哪些是“浅”哪些是“深”?通过实例来看:
#include"opencv2\core\core.hpp"
#include"opencv2\highgui\highgui.hpp"
using namespace cv;

int main(){
	Mat A=imread("D:\\1.jpg");   
	Mat B=A;
	Mat C(A);/*B、C都是浅拷贝,只复制矩阵指针,它们指向的是同一个内存空间,改变其中一个,剩下的两个也会受影响*/
	Mat D=A.clone();
	Mat E;
	A.copyTo(E); /*D、E是深拷贝,将图像数据也复制了一份,改变A不会影响D、E*/

	namedWindow("原来的A");imshow("原来的A",A);
	A=A-100;
	namedWindow("修改后的A");imshow("修改后的A",A);
	namedWindow("B");imshow("B",B);
	namedWindow("C");imshow("C",C);
	namedWindow("D");imshow("D",D);
	namedWindow("E");imshow("E",E);
	
	waitKey(0);
	return 0;
}

上面程序中已经注释哪些是“浅”/“深”。
总结一下,当调用Mat对象的函数成员clone()、copyTo()时,实现的是深拷贝,是将原矩阵的数据完全复制一份并且另外开辟一个内存空间来存储,如D、E。当用赋值或者构造函数来进行复制时,只是复制矩阵的指针,它们指向的是同一个内存空间,如B、C。
运行效果图:





你可能感兴趣的:(opencv,命令行模式,图像读取与显示)