Opencv入门(C++)

OpenCV(C++版)入门

一般来说大家看到一门新的知识都会很迷茫,也不知道该从哪下手,也不知道用什么软件,然后今天我来写一个OpenCV的入门,给大家开个头,看完这个开头之后基本也就知道应该怎么学OpenCV了。

实际上Opencv就是一个有关视觉处理的库,就和学C语言的时候用的math、time那一堆库一样,学习一个库的流程其实就是:
1.了解这个库是干什么的
2.学习这个库自带的一些函数应该如何使用,以及这些函数有什么效果
3.学了多个函数之后,通过对这些函数进行组合来实现一些复杂的功能。

强调一下这篇文章讲的是在WindowsC++语法的OpenCV,接下来的教程也是讲C++语法,不是python的。

然后说一下用什么软件来进行OpenCV的开发,一般的配置就是使用VS配置一个opencv的库来进行学习,下面附上所需的安装包链接。
VS2019 提取码:5162
Opencv-4.1.0提取码:n7lz
注意一下opencv的语法是有变革的,由开始的2到3,现在又更新到了4。其中3和4的语法大致相同,2和3在某些函数的参数上有一定的区别,所以在移植代码的时候,如果移过来发现报错,有可能是Opencv版本不一样,到时候改一下报错函数的参数就可以了。

安装的过程分四步:
1.装VS2019
2.装Opencv的库
3.把Opencv的库放到环境变量里
4.在VS里建一个工程,把这个工程连接上Opencv的库
具体步骤给大家一个我以前配的时候用的链接(步骤有些繁琐,我就不自己写了……)VS2019配置Opencv教程

因为是入门,所以先讲以下五个内容,都是些比较简单的函数,而且很有趣。
1.展示图片
2.灰度图片
3.模糊图片
4.边缘检测
5.保存图片

在进行操作之前,我们需要先放一张图片到自己新建的工程处,一我这个为例,我新建的工程是OpencvTest1,我找到这个工程main.cpp所在的路径,放了一张bilibili.jpg到这个地方。
在这里插入图片描述
1.展示图片

#include <opencv2/opencv.hpp>
#include <iostream>

using namespace std;
using namespace cv;

int main()
{
 Mat src = imread("bilibili.jpg");
 
 imshow("lalala",src);
 
 waitKey(0);
 return 0;
}

效果:出现一个小黑框和一张图片。
在这里插入图片描述
下面我们能来解释这段代码的内容。

#include <opencv2/opencv.hpp>  
#include <iostream> 
这两句话是分别引入opencv的库和c++的标准库
using namespace std;
using namespace cv;
这两句是引入工作空间,std是c++标准库的工作空间名,cv是opencv的工作空间名。
(工作空间的目的是避免 如果两个库有相同的函数名,在调用函数时发生冲突,
 上文这两个库里没有重复的函数名,所以直接引入工作空间不会有影响。)
int main()
{
 Mat src = imread("bilibili.jpg");
 
 imshow("lalala",src);
 
 waitKey(0);
 return 0;
}

//这一段是主函数。
Mat src = imread("bilibili.jpg");//其实是两条语句合在一起。分别为:
Mat src;//定义一个Mat类型的变量,变量名是src
src = imread("bilibili.jpg");//调用imread函数读取图片并把这张图片赋值给src。

imshow("lalala",src);//调用函数imshow展示图片,第一个参数lalala是显示图片所用的窗口的名字,src是上面刚刚被一张图片赋值的变量。

waitkey(0);//显示图片后开始等待下一步操作。如果不加这条命令的话,自己屏幕上会有一个黑框一闪而过,
//图片也不会显示出来,因为程序没有停下来,显示图片后直接关闭了程序。

return 0;//程序结束的标志,C语言上常用。因为这个主函数的返回值类型是int,所以最后返回一个0让程序结束。

这样一来一个最简单的Opencv程序就写好了,他的作用是调用一张图片并显示。
PS:
1.在使用 imread() 读取函数的时候如果图片处于main.cpp所在文件夹下时,可以直接输入图片的名字来进行读取图片。
当然我们也可以输入图片的绝对路径来进行读取图片。如imread(“D:\\vs\\OpencvTest1\\OpencvTest1\\bilibili.jpg”)
注意在分隔路径时我使用的是 “\\” 而不是 “\” ,因为按C/C++的语法,只写一个"\",可能会被当做转义字符,从而使"\“无法作用,所以要用”\\“来进行路径间的分隔。
当然不用”\\"的话也可以用/进行分隔,如:imread(“D:/vs/OpencvTest1/OpencvTest1/bilibili.jpg”)
2. imshow() 的第一个参数是窗口名
在这里插入图片描述

2.灰度图片
显示灰度图像的常规方式有两种:第一种是在读取图片的时候就按灰度格式读取。第二种是先读入图片,然后再转化图片。
第一种方法:

#include <opencv2/opencv.hpp>  
#include <iostream> 
using namespace std;
using namespace cv;
int main()
{
 Mat src = imread("bilibili.jpg",0);
 
 imshow("lalala",src);
 
 waitKey(0);
 return 0;
}
//可以发现其实和第一次的代码区别不大,只是修改了一下imread的参数
 Mat src = imread("bilibili.jpg",0);
 //imread()函数有两个参数,第一个参数是图片的路径或图片的名字,第二个参数是以何种格式来读取图片。
 //默认值是1,也就是原本的格式读取;如果输入参数为0的话就是以黑白格式读取。

效果:

在这里插入图片描述
第二种方法:
调用cvtColor()函数

#include <opencv2/opencv.hpp>  
#include <iostream> 
using namespace std;
using namespace cv;
int main()
{
 Mat src = imread("bilibili.jpg");
 Mat dst;
 cvtColor(src,dst,COLOR_BGR2GRAY);
 imshow("lalala",dst);
 
 waitKey(0);
 return 0;
}
//我们的操作是新建了一个Mat对象dst,又调用了函数cvtColor()来进行图片的灰度化,最终显示的图片也变成了dst。
 cvtColor(src,dst,COLOR_BGR2GRAY);//第一个参数是输入图像,第二个参数是输出图像,第三个参数是进行何种转换。
 //BGR2GRAY的意思是图片由BGR(三原色)格式变为灰度图格式。

效果:在这里插入图片描述
3.模糊图片
介绍模糊图片的时候,我们要先介绍三种形态学处理:腐蚀,膨胀,滤波。
腐蚀:erode() 将一张图片边界点去除。
膨胀:dilate() 对图像的边界进行扩张。
如下为膨胀和腐蚀的效果图,这两个操作正好是相反的,他们操作的组合还能组成开运算,闭运算,顶帽,黑帽等一系列形态学处理。

#include <opencv2/opencv.hpp>  
#include <iostream>
using namespace std;
using namespace cv;
int main()
{
 Mat src = imread("bilibili.jpg");
 imshow("src", src);
 Mat dst1,dst2;
 Mat element = getStructuringElement(MORPH_RECT, Size(15, 15));
 erode(src, dst1, element);
 imshow("erode",dst1);
 dilate(src, dst2, element);
 imshow("dilate", dst2);
 
 waitKey(0);
 return 0;
}

效果:在这里插入图片描述
滤波:滤波是用来去噪的,外界的干扰可能会掩盖图像的一些特征,使得图像变得模糊,使用滤波可以让图像特征更加明显。(PS:是特征更加明显,不一定代表图片看起来更加清晰。)

在讲图片滤波的原理之前先讲一些预备知识(划重点,这里很重要)。
首先我们前面定义那个可以接受图片的变量,它的类型是Mat,这其实是一种矩阵类型的变量。实际上图片就是一个大矩阵,比如我们看到一个像素值是100*100的图片,其实就是说这个图片是个100*100的大矩阵,矩阵上的每个值都是三原色混合出来的一种颜色,图片通过对每个像素点颜色的调节使得图片变得丰富多彩。(如果可以找到那种像素很低的图片,我们可以发现它几乎是由一个一个颜色不同得小方块构成的,那些小方块其实就是像素点。)
说完这些,我们就可以讲滤波的原理是什么了,我们得到一张图片,也就相当于得到一个大矩阵。我们先将这个大矩阵进行分区,比如把一个100*100的大矩阵分成25个4*4的小矩阵。所谓图像的特征其实就是矩阵上的值的特征,我们希望一个图像特征更加明显,就是希望该图像的像素值变得更有特点。所以我们可以对每个4*4小矩阵的值进行一些操作,比如找这些数的中位数、平均值、加权值,在找到特征值之后把矩阵中的值替换为特征值,这样我们图片的特征就更明显了。

我们举一个最常见的均值滤波的例子:
如果我们有一个大矩阵需要进行均值滤波,我们先在其中找一个小的3*3矩阵对它进行操作,实际上就是将九宫格最中间的值改为这个九宫格所有值的平均值。
因为(75+193+37+121+80+189+45+94+232)/9=118,所以我们将中间值80改为118.即:

75 193 37
121 80 189
45 94 232

变为

75 193 37
121 118 189
45 94 232

到此滤波原理结束,我们开始看一下效果。

#include <opencv2/opencv.hpp>  
#include <iostream>
using namespace std;
using namespace cv;
int main()
{
 Mat src = imread("bilibili.jpg");
 imshow("src", src);
 Mat dst;
 blur(src, dst, Size(7, 7));
 imshow("blur", dst);
 
 waitKey(0);
 return 0;
}

blur(src, dst, Size(7, 7));//1.输入图像,2.输出图像,
//3.进行滤波时选择小矩阵的大小(注意要要是n*n的矩阵,且n为奇数)。

效果:在这里插入图片描述
4.边缘检测
边缘检测其实就是找到图像上的边缘,很好玩,进行边缘检测的前提是先将图片灰度化,如果想边缘更清晰的话,可以在检测前加一步滤波。

如果对一个函数的参数不是很了解,可以去修改参数的值,看效果发生变化,就知道这个参数的影响在哪里了。

#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main()
{
 Mat src = imread("bilibili.jpg");
 imshow("src", src);
 Mat dst;
 cvtColor(src, src, COLOR_BGR2GRAY);
 blur(src, src, Size(3, 3));
 Canny(src, dst, 3, 9, 3);
 imshow("canny", dst);
 waitKey(0);
 return 0;
}
//流程:读图,灰度化,滤波,边缘检测。
 Canny(src, dst, 3, 9, 3);//1.输入2.输出3.最小阈值4.最大阈值5.sobel算子的大小
 //最大最小阈值用来使在阈值范围内的像素值才能保留。sobel算子的用处是与原图进行卷积运算,得到一个新的图,这个图根据阈值范围留下数据后就是效果图。

效果:
在这里插入图片描述
5.保存图片
只用一个函数imwrite()即可实现。

#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main()
{
 Mat src = imread("bilibili.jpg");
 imshow("src", src);
 Mat dst;
 cvtColor(src, src, COLOR_BGR2GRAY);
 blur(src, src, Size(3, 3));
 Canny(src, dst, 3, 9, 3);
 imshow("canny", dst);
 imwrite("canny.jpg",dst);
 waitKey(0);
 return 0;
}
//和上一个代码相比只加了一个函数imwrite("canny.jpg",dst);
imwrite("canny.jpg",dst);//第一个参数是图片名,记得加后缀。这里也可以写绝对路径。第二个参数是保存哪张照片,这里选择边缘检测之后的图片。

我们发现main.cpp所在文件夹下多了一张“canny.jpg”。在这里插入图片描述
文章到此结束,下一篇写一篇stm32有关流水灯的教程,因为发现上一篇讲配keil5配32的文章阅读量好多。
下一篇大概要隔一天再发,因为这个写起来好费时间,作业还莫得写完……

发布了5 篇原创文章 · 获赞 3 · 访问量 726

猜你喜欢

转载自blog.csdn.net/qq_43690756/article/details/105130236
今日推荐