分享

OpenCV Demo

 心不留意外尘 2016-03-26

from http://blog.csdn.net/u012162613/article/details/38779445

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 非命令行模式

非命令行模式,直接在程序中传参数,而不是在运行的时候再传递参数。
  1. <span style="font-size:18px;">#include<iostream>  
  2. #include"opencv2\core\core.hpp"  
  3. #include"opencv2\highgui\highgui.hpp"  
  4. using namespace cv;  
  5. using namespace std;  
  6.   
  7. int main(){  
  8.     /*opencv2版本,矩阵结构Mat,函数imread(),nameWindow(),imshow()*/  
  9.     Mat img1=imread("D:\\1.jpg");   //注意是双反斜杠,否则读不到图片  
  10.     if(!img1.data) {cout<<"error1";return -1;}   //检查有没有读到图片  
  11.     namedWindow("图片1");//有两个参数,第二个有默认形参  
  12.     imshow("图片1",img1);  
  13.     waitKey(10);  
  14.   
  15.     /*opencv老版本,数据结构IplImage,函数cvLoadImage(),cvNamedWindow(),cvShowImage()*/  
  16.     IplImage* img2=cvLoadImage("D:\\2.jpg");  
  17.     if(!img2)  {cout<<"error2";return -1;}   
  18.     cvNamedWindow("图片2");  
  19.     cvShowImage("图片2",img2);  
  20.     cvWaitKey(10);  
  21.     cvReleaseImage(&img2);  
  22.     cvDestroyWindow("图片2");   //老版本opencv需要手动释放内存  
  23.       
  24.     return 0;  
  25. }</span>  


opencv1与opencv2的区别?

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

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

2.2 命令行模式

  1. <span style="font-size:18px;">#include<iostream>  
  2. #include"opencv2\core\core.hpp"  
  3. #include"opencv2\highgui\highgui.hpp"  
  4. using namespace cv;  
  5. using namespace std;  
  6.   
  7. int main2(int argc,char** argv){  
  8.     /*opencv2版本,矩阵结构Mat,函数imread(),nameWindow(),imshow()*/  
  9.     Mat img1=imread(argv[1]);   //注意是双反斜杠,否则读不到图片  
  10.     if(!img1.data) {cout<<"error1";return -1;}   //检查有没有读到图片  
  11.     namedWindow("图片1");//有两个参数,第二个有默认形参  
  12.     imshow("图片1",img1);  
  13.     waitKey(10);  
  14.   
  15.     /*opencv老版本,数据结构IplImage,函数cvLoadImage(),cvNamedWindow(),cvShowImage()*/  
  16.     IplImage* img2=cvLoadImage(argv[2]);  
  17.     if(!img2)  {cout<<"error2";return -1;}   
  18.     cvNamedWindow("图片2");  
  19.     cvShowImage("图片2",img2);  
  20.     cvWaitKey(10);  
  21.     cvReleaseImage(&img2);  
  22.     cvDestroyWindow("图片2");   //老版本opencv需要手动释放内存  
  23.   
  24.     return 0;  
  25. }</span>  

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

  1. <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中的运行效果图:


3、再谈Mat

介绍Mat的特性,特别是Mat的复制构造。前面提到Mat包括信息头以及矩阵指针,矩阵指针指向的就是图片的内存空间,当我们要复制一张图片或者复制一个矩阵的时候,有很多种方法,但是必须注意复制有“浅复制”和“深复制”两种,哪些是“浅”哪些是“深”?通过实例来看:
  1. #include"opencv2\core\core.hpp"  
  2. #include"opencv2\highgui\highgui.hpp"  
  3. using namespace cv;  
  4.   
  5. int main(){  
  6.     Mat A=imread("D:\\1.jpg");     
  7.     Mat B=A;  
  8.     Mat C(A);/*B、C都是浅拷贝,只复制矩阵指针,它们指向的是同一个内存空间,改变其中一个,剩下的两个也会受影响*/  
  9.     Mat D=A.clone();  
  10.     Mat E;  
  11.     A.copyTo(E); /*D、E是深拷贝,将图像数据也复制了一份,改变A不会影响D、E*/  
  12.   
  13.     namedWindow("原来的A");imshow("原来的A",A);  
  14.     A=A-100;  
  15.     namedWindow("修改后的A");imshow("修改后的A",A);  
  16.     namedWindow("B");imshow("B",B);  
  17.     namedWindow("C");imshow("C",C);  
  18.     namedWindow("D");imshow("D",D);  
  19.     namedWindow("E");imshow("E",E);  
  20.       
  21.     waitKey(0);  
  22.     return 0;  
  23. }  

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





    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多