BY_ZZX
设计内容:
相机作为机器人传感器的一种,可以获取现实世界中的丰富信息,通过图像处理与计算机视觉算法,可以为机器人的移动提供指导。通过开源计算机视觉工具库(openCV)获取相机的图像,并利用该工具库实现图像处理中的图像分割等简单算法。设计内容如下:
1)调用openCV提供的API实现相机的读取余操作。
2)对于给定的矩形停车位场景,在对读取到的图像上利用颜色差别进行简单的阈值分割。
3)提取分割后的图像轮廓,并根据图像轮廓确定停车位边缘的四个角点。
设计过程:
1.在ubuntu下编译和配置openCV开源库
这一步可以参考别人的方法,CSDN有很多,我参考的是下面这个老哥的:
https://blog.csdn.net/cocoaqin/article/details/78163171
其中自然有很多的不解和疑惑,大概理解是一开始装的cmake是一个编译工具,OpenCV的编译是为了它的函数整合在系统之中。通过下面这三行代码可以实现读取电脑摄像头并且以视频的形式展现出来。
cmake .
make
./opencv_example
但是这个示例程序却存在一个bug:无法用鼠标×掉,×掉后立马自己又运行了起来。经过研读它的代码,发现是waitKey(n)函数的问题。waitKey函数删除就没法显示视频,如果关掉窗口,waitKey(n)函数没有读取键盘输入,程序会继续运行,这是一个冲突,所以通过鼠标×不了这个程序的运行。
2.学习openCV视觉库的数据结构表示,如图像的存储表示与基本操作。
openCV 自带的示例程序里主要用到了几个重要的库、类和函数:
<opencv2\highgui.hpp>:
包含了媒体输入输出,视频捕捉,图像视频编解码和图形接口等
imread():读取图像文件
imshow():在制定窗口显示文件
nameWindow():创建一个窗口
imwrite():输出图像文件
createTrackbar():创建一个滑条,跟某一个数值相连。
VideoCapture类:
VideoCapture ::××××××(/int device id/const string& filename)可以直接打开视频(文件和摄像头)。open也可以实现这样的功能
isOpened()是用来确认是否读取成功
release()是用来释放被读取的视频
grab()是用来抓取下一帧图像,成功则返回1,因此可以用来判断下一帧图像是否抓取成功
retreve()是用来返回刚刚抓取的视频帧
read()是调用grab(),retreve()
double get()是用来获取视频的参数的
bool set()是用来设置视频的参数的
还有另外一种获取视频帧的方法:是结合了Mat类,实例中运用了Mat image和capture >> image;这两个操作来实现。
Mat类:由于Mat类非常复杂,参考了callback博主的文章:https://blog.csdn.net/u010248552/article/details/79962132
添加水印的函数:putText():传入要添加水印的图像, 要加的字符, 字体, 粗细 , 颜色,添加位置等参数
waitKey(n):n为等待的时间,这个函数返回值为按键的ASCII码值,同事这个函数也是显示图形界面的接口,如果没有这个函数,读取到的摄像头图形就没法展现在显示器上。如果设置waitKey(0),则表示程序会无限制的等待用户的按键事件 。
openCV读取和显示图片:
error:在网上找了一份代码,复习粘贴然后make出现了两个错误:
stray ‘\240’ in program
stray ‘\302’ in program
在网上查了一下,240是非法ASCII字符,302是全角字符的问题。只能自己重新写一遍了,遇到了一些不懂的地方,查了一下:
imread(img.jpg,×××):其中后面一个参数是区分以原始图、灰度图、RGB图格式读取图片的三个方式,<0代表原始图,=0代表灰度图,>0代表RGB图(1,2,4)
cout<<endl:是输出结束符
namedWindow("name",***):后面一个参数是窗口大小相关的,1为自动调节窗口大小使之适应图片,2是鼠标可以调节窗口大小。注意这里是nameWindow而不是nameWindow。
destoryWindow("Window_name"):销毁窗口
重新写了一遍后,还是有很多error,发现注释的写法有问题,注释必须紧跟在代码后面且之间不能有空格。空行也有问题,代码区不能自己加空行进去。甚至行距也会有问题报错。
终于弄好了,编译通过,能显示图片出来。jpg图片由于是24位的,所以在imread中第二个参数传入2时,因为2代表anydepth,如果不是16或32位图,则会以8位图像读入,变成灰色;传入参数4时,因为4代表是anycolor,故仍然是彩色的;1代表color,所以也是彩色的。
能完成对图片的读取操作了,但是在ubuntu下却不能直接从word里面拷贝出里面的图片出来,于是安装了pinta:
sudo apt-get install -f
sudo apt-get install pinta
第一行代码是修复依赖包的,f:fix-broken,如果直接输入第二行代码,则会报错没有安装依赖包,并且在我的电脑上无法对磁盘进行写入。然后打开word,放大,按PrntScr键截图,用pinta裁剪,保存。
openCV对图像进行阈值分割和提取轮廓
参考了这位大神的博客:https://blog.csdn.net/MisterJiaJia/article/details/80464265
对其中的一些函数进行了研读:
cvtColor():
C++: void cvtColor(InputArray src, OutputArray dst, int code, int dstCn=0 );
. InputArray src: 原图像
. OutputArray dst: 变换后存储图像
. int code: 转换格式的标识
. int dstCn = 0: 目标图像通道数,如果取值为0,则由src和code决定
利用cvtColor可以把彩色图转换为灰度图,当然也可以在读取的时候就直接以灰度格式读入,直接以灰度读入会不会更快些呢?
error:
stray ‘\357’ in program
查了一下,357是代表在UTF8编码的文档中插入了中文的标点符号,检查了一下果然有个逗号写成了中文的。
threshold:
threshold的中文意思是门槛(n),临界的(adj)。这个函数的作用就是将灰度图像的灰度设置为0或255,使得图像凸显出黑白的效果,凸显出图像轮廓同时使数据量大大减少。函数定义:
double cv::threshold(InputArray Src,
OutputArray dst,
double thresh,
double Maxval,
int type,
)
第一个参数是输入图像,
第二个参数是输出图像,
第三个参数是阈值(thresh),
第四个参数是dst的最大值,
第五个参数是二值化的方式,具体见这位大神的博客:https://blog.csdn.net/u012566751/article/details/77046445
bug:我用一个char型变量存放阈值,结果不论怎么样设置阈值,图像都全白。折腾了半天,终于认识到自己的错误,太久没有调程序了,连char型变量的范围都忘了是-128~127。改成unsigned或者int就好。
getStructuringElement:
这个函数用于生成形态处理的核,定义如下:
getStructuringElement( int shape,//核的形状:0,十矩形;1,十字交叉形;3,椭圆形
Size ksize,//核的大小
Point anchor=Point(-1,-1)//核中心位置,默认位于图像中心处
)
这个核其实就是一个矩阵:
3*3的矩形矩阵
[1,1,1
1,1,1
1,1,1]
3*3的十字叉形矩阵
[0,1,0
1,1,1
0,1,0]
3*3的椭圆形矩阵
[0,1,0
1,1,1
1,1,1
1,1,1
0,1,0]
这个函数的返回值就是相应的形态学矩阵,需要用一个矩阵来存储,然后用于形态学处理。
morphologyEx():
这个函数是形态学变化函数,功能十分强大:
morphologyEx(InputArrary src,
OutputArray dst,
int op,
InputArray kernel,
Point anchor=Point(-1,-1),
intiterations= 1,
int borderType= BORDER_CONSTANT,
const Scalar&borderValue=morphologyDefaultBorderValue()
)
第三个参数,结构元素,表示形态学运算的类型:1.开运算:MORPH_OPEN;2.闭运算:MPRPH_CLOSE;3.形态梯度:MORPH_GRADIENT;4.“顶帽”:MORPH_TOPHAT(原图像与开图像之差);5.“黑帽”:MORPH_BLACKHAT(闭图像与原图像之差)
第四个参数anchor:结构元素的原点
第五个参数iterations:迭代的次数
详细介绍参考这位大神的博客:https://blog.csdn.net/keen_zuxwang/article/details/72768092
我经过处理之后的照片如下图: