概述
#【OpenCV教程】第二章 读取、显示、保存、修改图片
从昨日至今,从开始对OpenCV的懵懂到现在渐入佳境,带来部门的书籍也从之前的《人工智能-一种现代的方法变成OpenCV系列书籍,还花了不少银子从京东购入大量关于OpenCV的系列书籍!希望自己能取得更大进步,以此勉励自己,在看不到未来的道路上,依旧努力奔跑,不能停步。
OpenCV用C++编写,它的主要接口是C++,但是依然保留了大量C的接口。该库还有大量Python、Java、Matlab的接口,现如今也提供对C#、Ruby、Go的技术接口。
文章目录
- 本文主要思路
- OpenCV程序的基本流程图
- 利用OpenCV读取显示图片
- 重点函数解析
- 关于Mat
- imread() 函数
- imshow函数
- namedWindow()函数
- 输出图像到文件:imwrite()函数
- 滑动条的创建和使用
本文主要思路
本文主要讲述如何利用OpenCV读取、显示、保存以及修改图片
- 利用OpenCV读取显示图片
- 利用OpecCV保存图片
- 利用OpenCV修改图片
OpenCV程序的基本流程图
以下是我这两天使用OpenCV总结的一个基本流程图
基本标准的C++代码框架如下:
#include <iostream>
#include <opencv2/opencv.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui.hpp>
using namespace cv;
using namespace std;
int main(int argc, char** argv)
{
/******************************
* OpenCV读取Image的两种方式
* 1. 通过imread读取
* 2. 通过cvLoadImage读取
* 下面例举了两种方式的具体方法,选取其中一个即可
* 建议使用imread读取
******************************/
Mat image = imread(argv[1], 1);
Mat image = cvLoadImage(argv[1]);
// TODO: 对图像的具体操作
/******************************
* OpenCV中等待中断的方式有两种
* 1. cvWaitKey(0)
* 2. waitKey(0)
* 二者的区别是,有cv的是C语言的操作方式,当使用waitKey(0)时需要在代码前使用命名空间,using namespace cv
******************************/
cvWaitKey(0);
waitKey(0);
// 释放内存,破坏展示窗口
cvReleaseImage(image);
cvDestroyAllWindows();
return 0;
}
利用OpenCV读取显示图片
创建工程文件夹,小智学长使用的Mac操作系统,和第一章演示的一样,使用的是CMake,当然可以使用使用Mac下的XCode,或者Window下面的VS,根据自己实际使用的情况,输入以下代码,进行编译,执行即可。
> cd ~/Code/OpenCV # 这是小智学长Mac上存放OpenCV代码的地方
> mkdir ReadAndShow #创建工程文件夹ReadAndShow
> cd ReadAndShow #创建ReadAndShow文件夹
> touch ReadAndShow.cpp
> vim ReadAndShow.cpp
#输入以下C++代码
#include <iostream>
#include <opencv2/opencv.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui.hpp>
using namespace cv;
using namespace std;
int main(int argc, char** argv)
{
// 为方便操作,我们从命令行读取图片名称
if(argc != 2) {
cout << "Usage: ./ProjectName ImageName" << endl;
return -1;
}
Mat image = imread(argv[1], CV_LOAD_IMAGE_COLOR);
// 判断图片是否为空图片
if(!image.data) {
cout << "Could not open or find the image" << endl;
return -1;
}
// 创新一个窗口用于展示图片
namedWindow("Display image window", CV_WINDOW_AUTOSIZE);
imshow("Display image window", image);
waitKey(0);
return 0;
}
在ReadAndShow文件夹下创建CMakeLists.txt文件
> cd ReadAndShow
> touch CMakeLists.txt
> vim CMakeLists.txt
# 输入下面文件
project( ReadAndShow )
find_package( OpenCV REQUIRED )
add_executable( ReadAndShow ReadAndShow )
target_link_libraries( ReadAndShow ${OpenCV_LIBS} )
执行如下命令
> cmake .
> make
> ./ReadAndShow WechatIMG78.jpeg
可以得到如下结果:
![执行结果]
(https://img-blog.csdn.net/20180816142856349?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTIyNjY2MzQ=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70#pic_center=100x100)
重点函数解析
关于Mat
在2001年,OpenCV刚刚出来的时候,OpenCV是基于C语言开发的,为了在内存中存储照片,采用名为IplImage的C语言结果题,其中《学习OpenCV中文版》(清华大学出版社)中采用的就是IplImage的方式,所有大家以后买参考资料的时候可以暂时跳过这本书。采用C语言开发,在享受其便捷的同时,必须接受其不足,其中最大的问题就是内存管理,需要程序自己手动管理内存,在小程序和自己的demo中这点不是问题,但是在大型项目中,我们不能不重视这个问题。
在OpenCV2.0中,基于C++进行开发,引入类的概念,同时带来了另外一项便利,那就是自动内存管理。有点类似Python的内存管理,主要通过引用计数机制来实现,简而言之,就是有人引用Mat时,引用计数机制就加一,反之,就减一,当引用计数机制为零时,就会释放内存。
Mat主要由两部分组成:一个是矩阵头(包括矩阵的尺寸、存储方法和存储地址等信息),另外一个是指向存储所有像素值存储矩阵的指针。不妨站在设计者的角度思考?Mat类为什么要这样存储?众所周知,图像的操作中,开销最大的是矩阵的复制,而非矩阵头,局枕头的存储空间是固定而且相对矩阵而言是非常小的,因此为了避免不必要的开销,在运算的过程中,我们一般传递矩阵头。因此在复制操作中,我们往往也是复制矩阵头,当我们真正想要复制矩阵时,OpenCV为我们提供了两个函数clone()和copyTo()。
Mat的具体操作如下:
// 此处只创建矩阵头(有些书籍上叫做信息头,二者通用)
Mat imageFirst, imageSecond;
// 读取照片,并未矩阵开辟具体的存储空间,将存储地址写入矩阵头中
imageFirst = imread(argv[1], CV_LOAD_IMAGE_COLOR);
// 使用拷贝构造函数,只拷贝矩阵头和矩阵指针
Mat imageThird(imageFirst);
imageSecond = imageFrist;
// 真正拷贝矩阵的方式
Mat imageClone = imageFirst.clone();
Mat imageCopy;
imageFirst.copyTo(imageCopy);
// 我一直在寻找一种方式,希望写代码有写诗的感觉,相比有些博客动不动用A、B命名,我更像有一个更美妙的变量名。
TODO: 草稿,需要修改
imread() 函数
可以子啊OpenCV官方文档中查看到imread函数的原型:
Mat imread(const string& filename, int flags=1)
- 第一个参数,const string&类型的filename,填我们需要载入的图片路径名。
- 第二个参数,int类型的flags,为载入标识,它制定一个加载图像的颜色类型。可以看到它自带默认值1,所有有时候这个参数在调用时可以忽略。如果忽略,标识载入三通道的彩色图像。如果输入有冲突鄂标志,采用较小的数字值。另外如果以彩色模式载入图像,解码后的图像将以BGR的通道顺序进行存储,即蓝、绿、红的顺序,而不是通常的RGB的顺序。
imshow函数
imshow()函数用于在指定的窗口中显示一副图像,函数的原型如下:
void imshow(const string& winname, InputArray mat)
- 第一个参数:const string&类型的winname,填需要显示的窗口标识名称
- 第二个参数: InputArray类型的mat,填需要显示的图像
imshow函数用于在指定的窗口中显示图像,如果窗口是用CV_WINDOW_AUTOSIZE 标志创建的,那么显示图像的原始大小。否则,将图像将图像进行缩放以适合窗口。而imshow函数缩放图像,取决于图像的深度,具体如下:
- 如果载入的图像是8位无符号类型,就显示图像本来的样子
- 如果图像是16位无符号类型或32位整型,便用像素值除以256。也就是说,值得范围是[0, 255*256]映射到[0, 255].
- 如果图像是32位浮点型,像素值便要乘以255.也就是说,该值得范围是[0,1]映射到[0,255]。
namedWindow()函数
namedWindow函数用于创建一个窗口。若是简单地进行图片显示,可以略去namedWindow函数的调用,即先调用imread读入图片,然后用imshow函数指定出窗口名进行显示即可。
namedWindow函数的原型如下:
void namedWindow(const string& winname, int flags=WINDOW_AUTOSIZE)
- 第一个参数,const string&型的name,填写被用作窗口标识符的窗口名称
- 第二个参数,int类型的flags,窗口的标识,可以填写如下几种值
- WINDOW_NORMAL,设置这个值,用户可以改变窗口的大小(没有限制)。OpenCV2中还可以写成CV_WINDOW_NORMAL
- WINDOW_AUTOSIZE,设置这个值,窗口的大小会自动调整以适应现实的图像,并且用户不能手动改变窗口大小,OpenCV2中它还可以写成CV_WINDOW_AUTOSIZE。
- WINDOW_OPENGL,设置这个值,窗口创建的时候会支持OpenGL。OpenCV2中它还可以写成CV_WINDOW_OPENGL。
在通常情况下,namedWindow函数的默认值是WINDOW_AUTOSIZE,同时可以调用destroyWindow()或者destroyAllWindows()函数来关闭窗口,并取消之前分配的与窗口相关的所有内存空间。
输出图像到文件:imwrite()函数
在OpenCV中,输出图像到文件一般采用imwrite函数,它的声明如下:
bool imwrite(const string& filename, InputArray img, const vector& params=vector())
- 第一个参数,const string&类型的filename,填需要写入的文件名,注意要带上后缀。
- 第二个参数,InputArray类型的img,一般填一个Mat类型的图像数据
- 第三个参数,const vector&类型的params,表示为特定格式保存的参数编码,它的默认值为vector()
滑动条的创建和使用
滑动条(Trackbar)是OpenCV动态调节参数特别好用的一种工具,它依附于窗口而存在。
由于OpenCV中并没有实现按钮的功能,所有很多时候,我们还可以用仅含0-1的滑动条来实现按钮的按下,弹起效果。下面是createTrackbar的函数原型:
int createTrackbar(const string& trackbarname, const string& winname, int* value, int count, TrackbarCallback onChange=0, void* userdata=0)
最后
以上就是受伤小土豆为你收集整理的【OpenCV教程】第二章 读取、显示、保存以及修改图片的全部内容,希望文章能够帮你解决【OpenCV教程】第二章 读取、显示、保存以及修改图片所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复