目录
学过DSP(Digital Signal Processing 数字信号处理)之后,想必紧接着就要学习DIP(Digital Image Processing)了,DSP是对一维信号的处理,而DIP则是对二维图像的处理。OpenCv支持多种语言,这里使用的是Python,旨在学习OpenCv的同时,也去多尝试使用和熟悉Python(什么?为什么没有DSP的教程?因为DSP还没学明白,而且之前做的DSP都是使用matlab来实现的)
关于python的下载这里不再介绍了,下载完python之后都会附带一个pip工具。
本次项目主要会用到opencv-python和opencv-contrib-python两个python包。还记得怎么下载吗?在之前的一篇文章中提到过下载方式,但是并没有演示
python包可以使用pip快速而且十分方便的下载,具体步骤如下:
step1:
按下win+R(或者右键点“开始”,然后点运行)弹出运行框,输出cmd按下回车,进入命令提示行
step2:
输入以下指令下载opencv-python:
pip install opencv-python
包就会自动下载了(很炫酷的那种),
step3:
输入以下指令下载opencv-contrib-python
pip install opencv-contrib-python
step4:
测试导入包:
进入命令提示行,输入:
python
然后输入
import cv2
如果不报错,说明下载成功
也可以输入一下代码,查看全部已经下载的python包
pip list
输入以下代码,退出python
exit()
python编辑的IDE有许多:
1. PyCharm:JetBrains 公司开发的一款强大的 Python IDE,功能丰富,支持代码补全、调试、单元测试等功能。
2. Visual Studio Code:微软开发的轻量级代码编辑器,支持 Python 开发,通过安装插件可以实现调试、Linting 等功能。
3. Jupyter Notebook:基于 Web 的交互式 Python 环境,适合进行数据分析和可视化编程。
4. Spyder:科学计算和数据分析的 Python IDE,集成了 IPython 控制台、代码编辑器和变量查看器等功能。
5. Atom:GitHub 开发的文本编辑器,通过安装插件可以实现 Python 开发的功能。
6. Sublime Text:一款轻量级的文本编辑器,通过安装插件可以支持 Python 开发。
7. PyDev:Eclipse 的插件,提供了Python项目支持;适合有 Eclipse 使用经验的用户。
之前写的那个脚本是用vscode写的,对于轻量级的代码,用vscode当然没问题,但对于比较大型的项目,还是建议使用专门的IDE进行编辑。这里选择的是Pycharm
下载Pycharm步骤如下:
pycharm官网:
Download PyCharm: Python IDE for Professional Developers by JetBrains
pycharm有专业版
和社区版
专业版需要收费(当然,某多几块钱就能买来破解脚本),而社区版则是免费,社区版在官网下边,得往下翻一翻才能看到。下载之后就是一个.exe,点运行,下一步下一步,选择一个安装目录,下一步下一步就可以了。
OpenCV(Open Source Computer Vision Library)是一个开源的计算机视觉库,提供了丰富的图像处理和计算机视觉算法。OpenCV 最初由 Intel 开发,后来由 Willow Garage 接手维护。它可以在多个平台上运行,包括 Windows、Linux、Mac OS 等,支持多种编程语言,如 C++、Python、Java 等。
OpenCV 提供了许多功能和算法,包括但不限于:
1. 图像处理:包括图像加载、保存、显示、通道分离合并、图像滤波、颜色空间转换等。
2. 特征检测与描述:如 Harris 角点检测、SIFT、SURF、ORB 等特征点算法。
3. 目标检测:如 Haar 特征级联、HOG 特征分类器等。
4. 图像分割:如基于区域的分割、基于边缘的分割等。
5. 机器学习:OpenCV 与 ML 模块结合,可用于训练和应用机器学习模型。
6. 摄像头标定:用于相机校准和三维重建。
7. 视频分析:包括视频捕获、处理、分析和特征跟踪等。
OpenCV 受到广泛的应用,涵盖了计算机视觉、机器视觉、图像处理、模式识别等多个领域。开发者可以利用 OpenCV 快速实现各种图像处理和计算机视觉任务,同时通过社区的积极贡献,OpenCV 每天都在不断发展和完善。
总的来说,OpenCV 是一个功能强大的计算机视觉库,为开发者提供了丰富的工具和算法,帮助他们在图像处理和计算机视觉任务中取得成功。
我们可以使用CV2里的方法来进行读取一个图片和现实一个图片
import cv2 # 通道 img = cv2.imread('cat.jpg') cv2.imshow('img ', img ) cv2.waitKey(0) # 类似延时函数,单位ms。参数为0时,为按下任意键之后结束“延时“ cv2.destroyAllWindows()
我们读取到是下边这张图片,图片只要放在.py文件相同的目录即可。
我们知道,图片是有一个一个像素点组成的,RGB三原色组成了一张彩色的图片,对于黑白的图片,只需要知道亮度就可以获得一张图片。这里的RGB是三个数组,数组的大小等于图片的像素大小,数组里的每一个值的取值都为0到255,0对应黑,255对应最亮,也就是纯白。就像这样:
RGB三个数组,也就是对应三个颜色通道,三个颜色通道合在一起,就组成一张图片。
cv2.imread()函数,读取出来的就是一个三维数组,记录着RGB三个数组的值。
保存处理好的图片可以使用以下代码:
cv2.imwrite("out_img.jpg", cur_img) # 图片保存
使用PS也可以查看每个通道的信息:
RGB颜色通道的获取有两组简答的方法,一是直接将通过cv2.imread读取到的img的其中两个维度置为0,只留下其中一个维度,那就可以得到只包含其中一个颜色通道的数据了,需要注意的是,cv2读取的图片是GBR,跟我们常见的RGB刚好是反着的三个数组,因此在处理时需要注意,尤其是在使用非cv2的图片显示函数时,一定要先将GBR转化为RGB(下边的代码会提到)
import cv2 # 通道 img = cv2.imread('cat.jpg') cur_img = img.copy() # 让b和g都变为0,那就剩下r了,下同 cur_img[:, :, 0] = 0 # b g r cur_img[:, :, 1] = 0 # b g r cv2.imshow('r', cur_img)cv2.waitKey(0) # 类似延时函数,单位ms。参数为0时,为按下任意键之后结束“延时“ cv2.destroyAllWindows()
这里演示的是其中一个通道的获取,其他通道的获取也类似。
此外,cv2也提供了一个方法来获取RGB,注意这个方法获取到也是GBR,我们也可以通过GBR的值来重新合成一张图片
import cv2 # 通道 img = cv2.imread('cat.jpg') b, g, r = cv2.split(img) # 获取b g r三个通道img2 = cv2.merge([b, g, r]) # 根据bgr还原图像 cv2.imshow('img', img2) cv2.waitKey(0)
依次绘制RGB三个通道的图片如图:
图像填充简单点说,就是把图像四周填充上东西。OpenCv内置的有填充的方法,并提供了多种填充方式
import cv2 import matplotlib.pyplot as plt # 图像填充 img = cv2.imread('cat.jpg') img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # 将读取到的bgr转化为rgb top_size, bottom_size, left_size, right_size = (100, 100, 100, 100) # 设置需要填充的大小 # 图像填充 cropped_img1 = cv2.copyMakeBorder(img_rgb, top_size, bottom_size, left_size, right_size, borderType=cv2.BORDER_REPLICATE) cropped_img2 = cv2.copyMakeBorder(img_rgb, top_size, bottom_size, left_size, right_size, borderType=cv2.BORDER_REFLECT) cropped_img3 = cv2.copyMakeBorder(img_rgb, top_size, bottom_size, left_size, right_size, borderType=cv2.BORDER_REFLECT_101) cropped_img4 = cv2.copyMakeBorder(img_rgb, top_size, bottom_size, left_size, right_size, borderType=cv2.BORDER_WRAP) cropped_img5 = cv2.copyMakeBorder(img_rgb, top_size, bottom_size, left_size, right_size, borderType=cv2.BORDER_CONSTANT) # BORDER_REPLICATE:复制法,也就是复制最边缘像素。 # BORDER_REFLECT:反射法, 对感兴趣的图像中的像素在两边进行复制 # BORDER_REFLECT_101: 反射法, 也就是以最边缘像素为轴, 对称 # BORDER_WRAP: 外包装法 # BORDER_CONSTANT:常量法,常数值填充 fig, axs = plt.subplots(nrows=2, ncols=3) # 分区绘制图像 axs[0, 0].imshow(img_rgb) axs[0, 1].imshow(cropped_img1) axs[0, 2].imshow(cropped_img2) axs[1, 0].imshow(cropped_img3) axs[1, 1].imshow(cropped_img4) axs[1, 2].imshow(cropped_img5) plt.show() cv2.waitKey(0)
这里使用了plot绘图,并使用subplots进行分区(跟Matlab的方法好像很像,至少名字很像),因此在绘图前,需要将cv2读取到的GBR转化为RGB,也就是:
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # 将读取到的bgr转化为rgb
绘制出来的结果为:
图像融合是图像处理的一部分,这里以图像融合为例来介绍。
刚才已经提到了计算机眼里的图像是三个数组,那我们可不可以对数组进行操作呢?比如把数组的值+10?当然可以,处理起来就跟处理一个数组一样。同样,我们也可以将两个同样大小的数组进行融合,注意必须是同样大小的数组。我们这里在导入一个dog的图像
直接使用.shpe查看两个图像数组的大小
import cv2 # 图像融合和简单计算 img1 = cv2.imread('cat.jpg') img2 = cv2.imread('dog.JPEG') print(f"img1: {img1.shape}") print(f"img2: {img2.shape}")
我们发现两个图像不一样大,狗的图像更大,那我们就裁剪一下狗的图片,使之与猫一样大,然后使用cv2.add进行融合
img1 = cv2.resize(img1, (650, 433)) # 调整狗的大小,使之与猫的大小一致 # img2 = cv2.resize(img2, (0, 0), fx=0.5, fy=0.5) # 也可以不指定调整后的大小,而是指定调整后x,y的倍数 cv2.imshow('img', cv2.add(img1, img2)) # 显示融合后的图像(巨丑) cv2.waitKey(0)
这里要介绍一下cv2.add()与直接img1+img2的区别了,刚才已经提到,数组内的值取值范围是0到255,使用add函数,如果两个图形某个位置的值相加大于255,则会被置为255,而直接img1+img2的话,则得到的某个位置的值为该位置相加的值%255.
相加之后的图片巨丑,就不在演示了
图像阈值是一个大头,很多处理都会用到
cv2内置的也有阈值除了函数,跟图像填充一样,也提供了多种处理方式
阈值的除了主要是为了将图片二值化(或者说我遇到最多的就是二值化和边沿检查)
在现实图片之前,还是需要将RGB转化为GBR。threshold函数的第一个参数应是某一个通道的值。这次读取的图片是一个智能车比赛时的赛道
import cv2 import matplotlib.pyplot as plt # 阈值 img = cv2.imread('rode.png') b, g, r = cv2.split(img) # 二值化 ret1, thresh1 = cv2.threshold(b, thresh=127, maxval=255, type=cv2.THRESH_BINARY) ret2, thresh2 = cv2.threshold(b, thresh=127, maxval=255, type=cv2.THRESH_BINARY_INV) ret3, thresh3 = cv2.threshold(b, thresh=127, maxval=255, type=cv2.THRESH_TRUNC) ret4, thresh4 = cv2.threshold(b, thresh=127, maxval=255, type=cv2.THRESH_TOZERO) ret5, thresh5 = cv2.threshold(b, thresh=123, maxval=255, type=cv2.THRESH_TOZERO_INV) # cv2.THRESH_BINARY超过阈值部分取maxval(最大值),否则取O # cV2.THRESH_BINARY_INV THRESH_BINARY的反转 # cv2.THRESH_TRUNC大于阈值部分设为阈值,否则不变 # cv2.THRESH_TOZERO大于阈值部分不改变,否则设为O # cV2.THRESH_TOZERO_INV THRESH_TOZERO的反转 # 将 BGR 转化为 RGB img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) thresh1_rgb = cv2.cvtColor(thresh1, cv2.COLOR_RGB2BGR) thresh2_rgb = cv2.cvtColor(thresh2, cv2.COLOR_RGB2BGR) thresh3_rgb = cv2.cvtColor(thresh3, cv2.COLOR_RGB2BGR) thresh4_rgb = cv2.cvtColor(thresh4, cv2.COLOR_RGB2BGR) thresh5_rgb = cv2.cvtColor(thresh5, cv2.COLOR_RGB2BGR) # 显示图像 fig, axs = plt.subplots(nrows=2, ncols=3) axs[0, 0].imshow(img_rgb) axs[0, 1].imshow(thresh1_rgb) axs[0, 2].imshow(thresh2_rgb) axs[1, 0].imshow(thresh3_rgb) axs[1, 1].imshow(thresh4_rgb) axs[1, 2].imshow(thresh5_rgb) plt.show() # 绘制图像运行
结果如下图:
- import cv2
-
- # 通道
- img = cv2.imread('cat.jpg')
-
- cur_img = img.copy()
- # 让b和g都变为0,那就剩下r了,下同
- cur_img[:, :, 0] = 0 # b g r
- cur_img[:, :, 1] = 0 # b g r
- cv2.imshow('r', cur_img)
-
- cur_img = img.copy()
- cur_img[:, :, 0] = 0 # b g r
- cur_img[:, :, 2] = 0 # b g r
- cv2.imshow('g', cur_img)
-
- cur_img = img.copy()
- cur_img[:, :, 1] = 0 # b g r
- cur_img[:, :, 2] = 0 # b g r
- cv2.imshow('b', cur_img)
-
- cv2.waitKey(0) # 类似延时函数,单位ms。参数为0时,为按下任意键之后结束“延时“
- cv2.destroyAllWindows()
- # cv2.imwrite("out_img.jpg", cur_img) # 图片保存
- import cv2
-
- # 通道
- img = cv2.imread('cat.jpg')
- b, g, r = cv2.split(img) # 获取b g r三个通道
- # bb = img[:, :, 0] # 或者这样获取
- print(b)
- print(f"b.shape: {b.shape}")
- print(f"g.shape: {g.shape}")
- print(f"r.shape: {r.shape}")
- print(f"img.shape: {img.shape}")
-
- img2 = cv2.merge([b, g, r]) # 根据bgr还原图像
- cv2.imshow('img', img2)
- cv2.waitKey(0)
- import cv2
- import matplotlib.pyplot as plt
-
- # 图像填充
- img = cv2.imread('cat.jpg')
- img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # 将读取到的bgr转化为rgb
- top_size, bottom_size, left_size, right_size = (100, 100, 100, 100) # 设置需要填充的大小
-
- # 图像填充
- cropped_img1 = cv2.copyMakeBorder(img_rgb, top_size, bottom_size, left_size, right_size,
- borderType=cv2.BORDER_REPLICATE)
- cropped_img2 = cv2.copyMakeBorder(img_rgb, top_size, bottom_size, left_size, right_size,
- borderType=cv2.BORDER_REFLECT)
- cropped_img3 = cv2.copyMakeBorder(img_rgb, top_size, bottom_size, left_size, right_size,
- borderType=cv2.BORDER_REFLECT_101)
- cropped_img4 = cv2.copyMakeBorder(img_rgb, top_size, bottom_size, left_size, right_size,
- borderType=cv2.BORDER_WRAP)
- cropped_img5 = cv2.copyMakeBorder(img_rgb, top_size, bottom_size, left_size, right_size,
- borderType=cv2.BORDER_CONSTANT)
-
- # BORDER_REPLICATE:复制法,也就是复制最边缘像素。
- # BORDER_REFLECT:反射法, 对感兴趣的图像中的像素在两边进行复制
- # BORDER_REFLECT_101: 反射法, 也就是以最边缘像素为轴, 对称
- # BORDER_WRAP: 外包装法
- # BORDER_CONSTANT:常量法,常数值填充
- fig, axs = plt.subplots(nrows=2, ncols=3) # 绘制图像
-
- axs[0, 0].imshow(img_rgb)
- axs[0, 1].imshow(cropped_img1)
- axs[0, 2].imshow(cropped_img2)
- axs[1, 0].imshow(cropped_img3)
- axs[1, 1].imshow(cropped_img4)
- axs[1, 2].imshow(cropped_img5)
-
- plt.show()
-
- cv2.waitKey(0)
- import cv2
-
- # 图像融合和简单计算
- img1 = cv2.imread('cat.jpg')
- img2 = cv2.imread('dog.JPEG')
-
- print(f"img1: {img1.shape}")
- print(f"img2: {img2.shape}")
-
- img1 = cv2.resize(img1, (650, 433)) # 调整狗的大小,使之与猫的大小一致
-
- # img2 = cv2.resize(img2, (0, 0), fx=0.5, fy=0.5) # 也可以不指定调整后的大小,而是指定调整后x,y的倍数
-
- cv2.imshow('img', cv2.add(img1, img2)) # 显示融合后的图像(巨丑)
- cv2.waitKey(0)
- import cv2
- import matplotlib.pyplot as plt
-
- # 阈值
- img = cv2.imread('rode.png')
- b, g, r = cv2.split(img)
-
- # 二值化
- ret1, thresh1 = cv2.threshold(b, thresh=127, maxval=255, type=cv2.THRESH_BINARY)
- ret2, thresh2 = cv2.threshold(b, thresh=127, maxval=255, type=cv2.THRESH_BINARY_INV)
- ret3, thresh3 = cv2.threshold(b, thresh=127, maxval=255, type=cv2.THRESH_TRUNC)
- ret4, thresh4 = cv2.threshold(b, thresh=127, maxval=255, type=cv2.THRESH_TOZERO)
- ret5, thresh5 = cv2.threshold(b, thresh=123, maxval=255, type=cv2.THRESH_TOZERO_INV)
- # cv2.THRESH_BINARY超过阈值部分取maxval(最大值),否则取O
- # cV2.THRESH_BINARY_INV THRESH_BINARY的反转
- # cv2.THRESH_TRUNC大于阈值部分设为阈值,否则不变
- # cv2.THRESH_TOZERO大于阈值部分不改变,否则设为O
- # cV2.THRESH_TOZERO_INV THRESH_TOZERO的反转
-
- # 将 BGR 转化为 RGB
- img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
- thresh1_rgb = cv2.cvtColor(thresh1, cv2.COLOR_RGB2BGR)
- thresh2_rgb = cv2.cvtColor(thresh2, cv2.COLOR_RGB2BGR)
- thresh3_rgb = cv2.cvtColor(thresh3, cv2.COLOR_RGB2BGR)
- thresh4_rgb = cv2.cvtColor(thresh4, cv2.COLOR_RGB2BGR)
- thresh5_rgb = cv2.cvtColor(thresh5, cv2.COLOR_RGB2BGR)
-
- # 显示图像
- fig, axs = plt.subplots(nrows=2, ncols=3)
- axs[0, 0].imshow(img_rgb)
- axs[0, 1].imshow(thresh1_rgb)
- axs[0, 2].imshow(thresh2_rgb)
- axs[1, 0].imshow(thresh3_rgb)
- axs[1, 1].imshow(thresh4_rgb)
- axs[1, 2].imshow(thresh5_rgb)
-
- plt.show() # 绘制图像