【OpenCV学习】 《OpenCV3编程入门》--毛星云 01 邂逅OpenCV(OpenCV基本概念与基本架构)& ROS系统上的运用(python实现)

对 《OpenCV3编程入门》第一章的学习笔记:理解什么是计算机视觉,什么是OpenCV,以及其中的联系等等。

PS:此书为2014年出版,opencv的版本和接口也与现在有些不一致了,作此笔记主要是学习opencv基本理念与操作思路原理,感谢浅墨大神,这本书会和浅墨的思想一起历久弥新。

PS:作为学习笔记,我的思路是首先将此书读薄,然后去记忆关键知识点,形成自己学习opencv的架构

思维导图如下:

 

目录

1.1 OpenCV周边概念认知

         1.1.1 图像处理、计算机视觉与OpenCV

         1.1.2 OpenCV概述

         1.1.3 起源及发展

         1.1.4 应用概述

1.2 OpenCV基本架构分析

1.3 OpenCV3带来了什么

1.4 OpenCV的下载、安装与配置

1.5 快速上手OpenCV图像处理

1.5.1 读取图像与图像显示

1.5.2 图像腐蚀

1.5.3 图像模糊

1.5.4 边缘检测

 1.6 OpenCV视频操作基础

1.6.1 读取并播放视频

1.6.2 调用摄像机采集图像


1.1 OpenCV周边概念认知

1.1.1 图像处理、计算机视觉与OpenCV

        图像处理是指计算机对图像进行分析,从而达到所需的效果,一般包含图像压缩、增强和复原,匹配、描述和识别3个部分。

        图像处理一般指数字图像处理,数字图像是指用工业相机、摄像机、扫描仪等设备经过拍摄得到的一个大的二维数组。该数组的元素称为像素,其值称为灰度值。而数字图像处理是通过计算机对图像进行去噪、增强、复原、分割、提取特征等处理的方法和技术。

        计算机视觉是指用摄像机和电脑代替人眼对目标进行识别、跟踪和测量等机器视觉,并进一步做图形处理。

        图像处理和计算机视觉的区别在于:图像处理侧重于“处理”图像——如增强、还原、去噪、分割等等;而计算机视觉重点在于使用计算机来模拟人的视觉,因此模拟才是计算机视觉领域的最终目标。

 1.1.2 OpenCV概述

        OpenCV(Open Source Computer Vision Library),是基于开源发行的跨平台计算机视觉库,它实现了图像处理和计算机视觉方面的通用算法。

        OpenCV于1999年由Intel建立,如今由Willow Garage支持。它是一个基于开源发行的跨平台计算机视觉库,可以运行在Linux、Windows、Mac OS、Android、iOS等操作系统上。OpenCV由一系列C函数和C++类构成,轻量且高效,同时提供C++、Python、Ruby、MATLAB等语言的接口,实现了图像处理和计算机视觉方面的很多通用算法。

         OpenCV的设计目标是执行速度尽量快,主要关注实时应用。它采用优化的C/C++代码编写,能够充分利用多核处理器的优势;其主要目标是建立一个简单易用的计算机视觉框架,来帮助开发用户更快更便捷地设计更复杂的计算机视觉应用。

         OpenCV覆盖了计算机视觉的多个应用领域,如工厂产品检测、医学成像、信息安全、用户界面、摄像机标定、立体视觉和机器人等。

 OpenCV官网主页:Home - OpenCV

 OpenCV Github主页:https://github.com/Itseez/opencv

       OpenCV 开发板Wiki主页:http://code.opencv.org

 1.1.3 起源及发展

        OpenCV项目最早由Intel公司于1999年启动,旨在促进CPU密集型应用。

        在Intel的性能库团队的帮助下,OpenCV实现了一些核心代码和算法,并发给了Intel俄罗斯的库团队,由此,OpenCV的诞生,发源于Intel,实现和优化于俄罗斯。

        在开始之初,OpenCV有以下三大目标

  •  为基本的视觉应用提供开放且优化的开源代码,避免“闭门造车”
  • 提供通用框架传播视觉知识,代码易读且可改写
  • OpenCV库采用的协议不要求商业产品继续开发代码,促进基于视觉的商业应用发展

 1.1.4 应用概述

  • 人机交互
  • 物体识别
  • 图像分区
  • 人脸识别
  • 动作识别
  • 运动跟踪
  • 机器人 

 1.2 OpenCV基本架构分析

        通过OpenCV安装路径下的include目录里面的头文件的分类存放,来一窥OpenCV的组件架构

        进入到..\opencv\build\include目录,可以看到opencv和opencv2这两个文件夹,opencv为旧版头文件,opencv2为新版头文件

         在..\opencv\build\include\opencv2目录下,有个名为opecv_modules.hpp的文件,存放的是OpenCV2中与新模块构造相关的说明代码,其定义了OpenCV2中所有组件的宏

此方法应与opencv3一致,只是更新换代的区别。

OpenCV所有模块
模块名称模块内容
【calib3d】Calibration(校准)和3D这两次的组合缩写。主要是相机校准和三维重建相关的内容,包括基本的多视角几何算法、单个摄像头标定、物体姿态估计、立体相似性算法、3D信息的重建等。
【contrib】Contributed/Experimental Stuf的缩写。新增人脸识别、立体匹配、人工视网膜模型等技术。
【core】核心功能模块
  • OpenCV基本数据结构
  • 动态数据结构
  • 绘图函数
  • 数组操作相关函数
  • 辅助功能与系统函数和宏
  • 与OpenGL的互操作
【imgproc】Image和Process这两个单词的组合缩写。图像处理模块。
  • 线性和非线性的图像滤波
  • 图像的几何变换
  • 其他(Miscellaneous)图像转换
  • 直方图相关
  • 结构分析和形状描述
  • 运动分析和对象跟踪
  • 特征检测
  • 目标检测等内容
【features2d】

2D功能框架

  • 特征检测和描述
  • 特征检测器(Feature Detectors)通用接口
  • 描述符提取器(Description Extractors)通用接口
  • 描述符匹配器(Description Matchers)通用接口
  • 通用描述符(Generic Descriptor)匹配器通用接口
  • 关键点绘制函数和匹配功能绘制函数
【flann】

高维的近似近邻快速搜索算法库

  • 快速近似最近邻搜索
  • 聚类
【gpu】运用GPU加速的计算机视觉模块
【highgui】高层GUI图形用户界面,包含媒体的输入输出、视频捕捉、图像和视频的编码解码、图形交互界面的接口等内容。
【legacy】一些已废弃的代码库
【ml】

机器学习模块,基本上是统计模型和分类算法

  • 统计模型
  • 一般贝叶斯分类器
  • K-近邻
  • 支持向量机
  • 决策树
  • 提升
  • 梯度提高树
  • 随机数
  • 超随机数
  • 期望最大化
  • 神经网络
  • MLData
【nonfree】一些具有专利的算法模块,包含特征检测和GPU相关的内容
【objdetect】目标检测模块,包含Cascade Classification(级联分类)和Latent SVM这两部分。
【ocl】运用OpenCL加速的计算机视觉组件模块
【photo】

包含图像修复和图像去噪两部分

【stitching】图像拼接模块
  • 拼接流水线
  • 特点寻找和匹配图像
  • 估计旋转
  • 自动校准
  • 图片歪斜
  • 接缝估测
  • 曝光补偿
  • 图片混合
【superres】超分辨率技术的相关功能模块
【ts】OpenCV测试相关代码
【video】视频分析组件,包括运动估计、背景分离、对象跟踪等视频处理相关内容
【Videostab】视频稳定相关组件

可以这么说,OpenCV就是多模块组合的SDK。


 1.3 OpenCV3带来了什么

这部分可能有点过时了,就跳过了,有兴趣的读者可以读读文中相关部分。


1.4 OpenCV的下载、安装与配置

 同理,根据自身设备进行下载安装。

我使用的是ROS系统,20.04 noetic,那么使用以下命令就可以进行安装了

$ sudo apt install ros-noetic-vision-opencv libopencv-dev python3-opencv 

默认安装的版本是opencv4,安装好后的文件放置在/usr/include/opencv4/opencv2中,上文提及到的opecv_modules.hpp同样放置在此文件夹中,其中涉及的模块会有所不同

#define HAVE_OPENCV_ARUCO
#define HAVE_OPENCV_BGSEGM
#define HAVE_OPENCV_BIOINSPIRED
#define HAVE_OPENCV_CALIB3D
#define HAVE_OPENCV_CCALIB
#define HAVE_OPENCV_CORE
#define HAVE_OPENCV_DATASETS
#define HAVE_OPENCV_DNN
#define HAVE_OPENCV_DNN_OBJDETECT
#define HAVE_OPENCV_DNN_SUPERRES
#define HAVE_OPENCV_DPM
#define HAVE_OPENCV_FACE
#define HAVE_OPENCV_FEATURES2D
#define HAVE_OPENCV_FLANN
#define HAVE_OPENCV_FREETYPE
#define HAVE_OPENCV_FUZZY
#define HAVE_OPENCV_HDF
#define HAVE_OPENCV_HFS
#define HAVE_OPENCV_HIGHGUI
#define HAVE_OPENCV_IMG_HASH
#define HAVE_OPENCV_IMGCODECS
#define HAVE_OPENCV_IMGPROC
#define HAVE_OPENCV_LINE_DESCRIPTOR
#define HAVE_OPENCV_ML
#define HAVE_OPENCV_OBJDETECT
#define HAVE_OPENCV_OPTFLOW
#define HAVE_OPENCV_PHASE_UNWRAPPING
#define HAVE_OPENCV_PHOTO
#define HAVE_OPENCV_PLOT
#define HAVE_OPENCV_QUALITY
#define HAVE_OPENCV_REG
#define HAVE_OPENCV_RGBD
#define HAVE_OPENCV_SALIENCY
#define HAVE_OPENCV_SHAPE
#define HAVE_OPENCV_STEREO
#define HAVE_OPENCV_STITCHING
#define HAVE_OPENCV_STRUCTURED_LIGHT
#define HAVE_OPENCV_SUPERRES
#define HAVE_OPENCV_SURFACE_MATCHING
#define HAVE_OPENCV_TEXT
#define HAVE_OPENCV_TRACKING
#define HAVE_OPENCV_VIDEO
#define HAVE_OPENCV_VIDEOIO
#define HAVE_OPENCV_VIDEOSTAB
#define HAVE_OPENCV_VIZ
#define HAVE_OPENCV_XIMGPROC
#define HAVE_OPENCV_XOBJDETECT
#define HAVE_OPENCV_XPHOTO

1.5 快速上手OpenCV图像处理

1.5.1 读取图像与图像显示

读取图像只需要使用imread函数即可,图像显示只需要使用imshow函数即可。

#!/usr/bin/env python3
import rospy
import cv2

rospy.init_node("showimg") 
img = cv2.imread("/home/spark/Pictures/bluebox.png")
cv2.imshow('box',img)
cv2.waitKey(0)

然后在终端输入以下命令:

rosrun opencv_learn showimg.py

 那么,对代码部分进行解析:

  1. #!/usr/bin/env python3  #告诉操作系统执行这个脚本的时候,调用/usr/bin下的python3解释器
  2. import rospy #导入ros python库
    import cv2 #导入opencv的库
  3. rospy.init_node("showimg")  #初始化ros节点,创建名为showmsg的节点
  4. img = cv2.imread("/home/spark/Pictures/bluebox.png") #使用imread读取绝对路径下的图片文件
  5. cv2.imshow('box',img) #使用imshow函数,后面接的是显示的窗口名和显示对象
  6. cv2.waitKey(0) #调用waitKey函数等待按键按下,以便让窗口一直显示,直到有按键按下

 由于在显示过程中,图像窗口过于大,影响到观察与操作了,所以添加窗口调节大小的部分:

#!/usr/bin/env python3
import rospy
import cv2

rospy.init_node("showimg") 
img = cv2.imread("/home/spark/Pictures/bluebox.png")
cv2.namedWindow("box",0)
cv2.resizeWindow("box",500,500)
cv2.imshow('box',img)
cv2.waitKey(0)

  1.  cv2.namedWindow("box",0) # 创建一个空窗口,名为box
  2. cv2.resizeWindow("box",500,500) # 调整窗口的大小,指定窗口的名称,设置宽度与高度 

 如此,就能方便用户观察了。
 

1.5.2 图像腐蚀

图像腐蚀是指用图像中的暗色部分“腐蚀”掉图像中的高亮部分。

使用getStructuringElement函数获取指定形状和尺寸结构元素,代表进行腐蚀操作时使用的结构类型。

#!/usr/bin/env python3
import rospy
import cv2

rospy.init_node("showimg") 
img = cv2.imread("/home/spark/Pictures/bluebox.png")
cv2.namedWindow("erode_box",0)
cv2.resizeWindow("erode_box",500,500)

kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(15,15))
img = cv2.erode(img,kernel)

cv2.imshow('erode_box',img)
cv2.waitKey(0)

 然后在终端输入以下命令:

rosrun opencv_learn erodeimg.py

 基本的读取操作没有变化,只是在此基础上添加了腐蚀的操作

1. kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(15,15))

定义一个kernel核心,由getStructuringElement函数设定一个结构类型

cv2.getStructuringElement(shape, ksize) 
  • shape:代表形状类型
    • cv2. MORPH_RECT:矩形结构元素,所有元素值都是1
    • cv2. MORPH_CROSS:十字形结构元素,对角线元素值都是1
    • cv2. MORPH_ELLIPSE:椭圆形结构元素
  • ksize:代表形状元素的大小

2.  img = cv2.erode(msg,kernel)

	dst	=	cv.erode(	src, kernel[, dst[, anchor[, iterations[, borderType[, borderValue]]]]]	)

其中:

  • src 是需要腐蚀的原始图像
  • kernel 代表腐蚀操作时所采用的结构类型。
  • anchor 代表element结构中锚点的位置,默认为(-1,-1),在核的中心位置。
  • iterations 是腐蚀操作的迭代的次数,默认为1
  • borderType 代表边界样式

opencv官方文档 cv2.erodehttps://docs.opencv.org/4.1.2/d4/d86/group__imgproc__filter.html#gaeb1e0c1033e3f6b891a25d0511362aeb

1.5.3 图像模糊

使用均值滤波操作的blur函数

#!/usr/bin/env python3
import rospy
import cv2

rospy.init_node("blurimg") 
img = cv2.imread("/home/spark/Pictures/bluebox.png")
cv2.namedWindow("blurbox",0)
cv2.resizeWindow("blurbox",500,500)

img = cv2.blur(img,(15,15))

cv2.imshow('blurbox',img)
cv2.waitKey(0)

 

 dst = blur(src, ksize, dst=None, anchor=None, borderType=None)

均值滤波器,也称低通滤波器
顾名思义,均值滤波器即对滤波核内的数据求均值,然后将这个值赋值给矩阵核心位置。
均值滤波器可以使用cv2.blur() 方法实现

  • src:图像
  • ksize:滤波核大小,使用元组表示,如(a,b)a表示height(高度),b表示width(宽度)。
  • anchor:波核锚点
  • borderType:边界类型

详细使用方法可查看

【学习笔记】ROS 中常用opencv操作_Howe_xixi的博客-CSDN博客_ros的opencvopencv中一些常用函数笔记https://blog.csdn.net/weixin_44362628/article/details/124888288?spm=1001.2014.3001.5502

 1.5.4 边缘检测

使用canny进行边缘检测。首先载入图像,将其转成灰度图,再使用blur函数进行图像模糊以降噪,再使用canny函数进行边缘检测。

#!/usr/bin/env python3
import rospy
import cv2

rospy.init_node("cannyimg") 
img = cv2.imread("/home/spark/Pictures/bluebox.png")
cv2.namedWindow("cannyimg",0)
cv2.resizeWindow("cannyimg",500,500)

# gray
gray_img = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

# blur
blur_img = cv2.blur(gray_img,(10,10))
#cv2.imshow('blur_img',blur_msg)

# canny
Canny_img = cv2.Canny(blur_img,60,110)

cv2.imshow('cannyimg',Canny_img)
cv2.waitKey(0)

 

 Canny 边缘检测分为如下几个步骤:
步骤 1:去噪。噪声会影响边缘检测的准确性,因此首先要将噪声过滤掉。
步骤 2:计算梯度的幅度与方向。
步骤 3:非极大值抑制,即适当地让边缘“变瘦”。
步骤 4:确定边缘。使用双阈值算法确定最终的边缘信息。

edges = cv.Canny( image, threshold1, threshold2[, apertureSize[, L2gradient]])

其中:

  • edges 为计算得到的边缘图像。
  • image 为 8 位输入图像。
  • threshold1 表示处理过程中的第一个阈值。
  • threshold2 表示处理过程中的第二个阈值。
  • apertureSize 表示 Sobel 算子的孔径大小。
  • L2gradient 为计算图像梯度幅度(gradient magnitude)的标识。其默认值为 False。如果为 True,则使用更精确的 L2 范数进行计算(即两个方向的导数的平方和再开方),否则使用 L1 范数(直接将两个方向导数的绝对值相加)。

 1.6 OpenCV视频操作基础

利用VideoCapture对视频进行读取显示,以及调用摄像头。

1.6.1 读取并播放视频

我暂时还没用到使用opencv处理视频的情况,所以暂且留住,待后续涉及到视频的操作的时候会补上。文中也是用简单的几个语句即可实现视频的载入和读取视频帧了。

1.6.2 调用摄像机采集图像

由于是在ROS上执行,采用订阅话题的方式获取摄像机的画面,然后使用opencv进行处理,如灰度化后的canny边缘检测。

在运行程序前要记得启动摄像机。

#!/usr/bin/env python3
import rospy
import cv2
from sensor_msgs.msg import Image
from cv_bridge import CvBridge


def image_cb(img):
    
    prime_img = CvBridge().imgmsg_to_cv2(img, "bgr8")
    cv2.imshow("prime_img",prime_img)

    cv2.namedWindow("cannyimg",0)
    cv2.resizeWindow("cannyimg",500,500)

    # gray
    gray_img = cv2.cvtColor(prime_img,cv2.COLOR_BGR2GRAY)

    # blur
    blur_img = cv2.blur(gray_img,(10,10))
    #cv2.imshow('blur_img',blur_msg)

    # canny
    Canny_img = cv2.Canny(blur_img,60,110)

    cv2.imshow('cannyimg',Canny_img)
    cv2.waitKey(1)

rospy.init_node('camera_canny', anonymous=False)
rospy.Subscriber("/camera/color/image_raw", Image, image_cb, queue_size=1)
rospy.spin()

 对上面的代码进行一下解释吧。

首先导入头文件部分:
from sensor_msgs.msg import Image # 传入的图片消息格式
from cv_bridge import CvBridge # CVBridge 主要用作将ros的图像格式转换为opencv能够处理的格式,下文会有所提及

接下来是创建订阅者部分,负责接受摄像机的图像画面:

rospy.Subscriber("/camera/color/image_raw", Image, image_cb, queue_size=1)
rospy.spin()

订阅的是彩色图像画面,数据类型为Image,接受到信息的时候就会进入到image_cb回调函数进行处理了。使用订阅时记得在后面加上rospy.spin()语句,作为等待服务的循环语句,不然程序接受不到信息时就会直接跳出了。

 最后是回调函数image_cb中的内容解释:

def image_cb(img):
    
    prime_img = CvBridge().imgmsg_to_cv2(img, "bgr8")
    cv2.imshow("prime_img",prime_img)

    cv2.namedWindow("cannyimg",0)
    cv2.resizeWindow("cannyimg",500,500)

    # gray
    gray_img = cv2.cvtColor(prime_img,cv2.COLOR_BGR2GRAY)

    # blur
    blur_img = cv2.blur(gray_img,(10,10))
    #cv2.imshow('blur_img',blur_msg)

    # canny
    Canny_img = cv2.Canny(blur_img,60,110)

    cv2.imshow('cannyimg',Canny_img)
    cv2.waitKey(1)

操作和之前的canny边缘检测类似,只是在处理传入的图像数据img之前,需要使用cvbridge将图像格式进行一次变换,转换成opencv能够处理的图像格式,如8进制的bgr图像。

cv2.waitKey()也需要从原来的0改成1,否则只会读取视频中的一帧后等待。


至此,学习完了书中的第一章,并将其应用在ROS noetic 的opencv4中。

  • 3
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值