本文首发于:行者 AI
OpenCV 是一个基于 BSD 许可(开源)发行的跨平台的计算机视觉和机器学习软件库,能够运行在 Linux、Windows、Android 和 Mac OS 操作系统上。它轻量级而且高效——由一系列 C 函数和大量 C++ 类形成,同时提供了 Python、Ruby、MATLAB 等语言的接口,实现了图像处理和计算机视觉方面的很多通用算法。
OpenCV 在图像宰割、人脸识别、物体辨认、动作跟踪、动作剖析、机器视觉等畛域都有宽泛的利用。
以下是 OpenCV 的基本操作及其利用案例。
1. OpenCV 基本操作
1.1 读取、显示以及保留操作
import cv2
image = cv2.imread("test.jpg") # 读取操作
cv2.imshow("test", image) # 显示操作
cv2.waitKey() # 期待按键
cv2.imwrite("save.jpg") # 保留操作
1.2 扭转色调空间
image = cv2.imread("test.jpg")
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV) # 转换到 HSV 空间
hls = cv2.cvtColor(image, cv2.COLOR_BGR2HLS) # 转换到 HLS 空间
lab = cv2.cvtColor(image, cv2.COLOR_BGR2Lab) # 转换到 Lab 空间
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # 转换到 GRAY 空间(灰度图)
HSV 这个模型中色彩的参数别离是:色调(H),饱和度(S),明度(V),该模型罕用来做绿幕宰割。
在图像检测中,能够对样本进行色调空间转换实现数据加强,如将训练数据间接转换到 HSV 空间,或者调整 V(明度)通道的大小,扭转图片的明暗,再转到 BGR 格局。
1.3 几何变换 – 缩放、平移、旋转
a. 缩放
image = cv2.imread("test.jpg")
resize = cv2.resize(image, (), fx=0.5, fy=0.5, interpolation=cv2.INTER_AREA) # 长宽放大到 0.5 倍
b. 平移
在对图像作平移操作时,需创立 2 行 3 列变换矩阵,M 矩阵示意程度方向上平移为 x,竖直方向上的平移间隔为 y。
import cv2
import numpy as np
image = cv2.imread("test.jpg")
rows, cols, channels = image.shape
M = np.float32([[1,0,100],[0,1,50]])
res = cv.warpAffine(image, M, (cols, rows))
c. 旋转
旋转所需的变换矩阵能够通过函数 cv2.getRotationMatrix2D 失去。
image = cv2.imread('test.jpg')
rows, cols, channels = image.shape
rotate = cv2.getRotationMatrix2D((rows*0.5, cols*0.5), 45, 1) # 第一个参数:旋转中心点 第二个参数:旋转角度 第三个参数:缩放比例
res = cv2.warpAffine(image, rotate, (cols, rows))
1.4 平滑解决 – 含糊、滤波
含糊滤波操作去除图像中的椒盐噪声、进步图像的对比度、实现锐化解决、进步立体感等。
image = cv2.imread('test.jpg')
blur = cv2.blur(image, (5, 5)) # 均值滤波 第二个参数是卷积核大小
median_blur = cv2.medianBlur(image, 5) # 中值滤波
gaussian_blur = cv2.GussianBlur(image, (5, 5)) # 高斯含糊
1.5 收缩、侵蚀
a. 图像形态学操作
图像形态学操作是基于形态的一系列图像处理操作的合集,次要是基于集合论根底上的形态学数学。
- 形态学有四个基本操作:侵蚀、收缩、开、闭
- 收缩与侵蚀是图像处理中最罕用的形态学操作伎俩
- 收缩就是图像中的高亮局部进行收缩,“畛域扩张”,效果图领有比原图更大的高亮区域。侵蚀就是原图中的高亮局部被侵蚀,“畛域被鲸吞”,效果图领有比原图更小的高亮区域
b. 收缩与侵蚀
它们能实现多种多样的性能,次要如下:
- 打消噪声
- 宰割出独立的图像元素,在图像中连贯相邻的元素
- 寻找图像中的显著的极大值区域或极小值区域
- 求出图像的梯度
image = cv2.imread("test.jpg")
kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(3, 3)) # 获取卷积核
eroded = cv2.erode(image, kernel) # 侵蚀图像
dilated = cv2.dilate(image, kernel) # 收缩图像
c. 开运算和闭运算
- 开运算:先侵蚀后收缩,用于移除由图像乐音造成的斑点
- 闭运算:先收缩后侵蚀,用来连贯被误分为许多小块的对象
1.6 查找绘制轮廓
a. 查找轮廓
轮廓查找在图像检测畛域有很宽泛的利用, 比方查找图像中显著的色块、条纹、物体边缘等等,查找轮廓前先要对图像进行二值化解决。
# opencv 版本大于 3
contours, hierarchy = cv2.findContours(image, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) # 第一个参数:查找的二值图像 第二个参数:轮廓检索模式 第三个参数:轮廓近似办法
# 返回值 contours 为查找到的轮廓列表,hierarhy 为轮廓之间的层级关系
b. 绘制轮廓
查找到轮廓后能够通过 drawContours 函数绘制出轮廓
cv2.drawContours(temp,contours,-1,(0,255,0),3) # 第一个参数:画布,能够是原图 第二个参数:查找到的轮廓 第三个参数:- 1 示意全画 第四个参数:色彩 第五个参数:轮廓宽度
2. OpenCV 的工程利用 - 色块检测
2.1 问题背景
游戏画面因为美术资源缺失、程序 bug 都会产生各种色块,常见的有红色、紫色等,怎么通过程序筛选出这类异样画面,放慢测试过程呢?
2.2 问题剖析
通过观察,咱们发现色块类的异样都是一些比拟规定的矩形图像,色调差很显著,基于这些特点,咱们能够很容易的筛选杰出块。
2.3 程序设计
a. 图像二值化
通过 RGB 通道的数值大小剔除掉其它的色彩,失去黑白二值图
import cv2
import numpy as np
image = cv2.imread("test.jpg")
b, g, r = cv2.split(self.image) # 拆散 B、G、R 通道
b = np.where(b >= 250, 1, 0) # 找到 G 通道符合要求的像素点置 1,不合乎置 0
g = np.where(g >= 250, 1, 0) # 找到 G 通道符合要求的像素点置 1,不合乎置 0
r = np.where(r >= 250, 1, 0) # 找到 G 通道符合要求的像素点置 1,不合乎置 0
gray = b + g + r # 将三个通道叠加成一个通道
gray = np.where(gray==3, 255, 0).astype(np.uint8) # 像素点为 3 的即为满足要求的点设置为红色,不合乎设置为彩色
b. 查找轮廓
失去的黑白二值图因为除了色块外其它图像地位也有靠近色块色彩的地位被保留了下来,须要剔除
通过查找二值图轮廓的办法咱们能够筛选出拆散的小色块
contours, hierarchy = cv2.findContours(gray, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) # 获取轮廓及层级关系
c. 轮廓筛选
通过轮廓周长和面积剔除掉小色块,这些色块很可能就是提取的失常区域色彩较类似的点。
def screen_contour(contour):
contour_area = cv2.contourArea(contour)
if contour_area > self.area_limit:
return True
return False
pass_contours = []
for contour in contours:
if screent_contour(contour):
pass_contours.append(contour)
因为色块更靠近于矩形,咱们能够通过轮廓计算杰出块的宽和高,色块的面积能够估算进去,色块面积与估算面积越靠近,阐明检测到的色块更靠近矩形,通过这个办法,能够筛选出大部分不规则的色块。
def screent_contour(contour):
width = np.max(contour[:,:,0]) - np.min(contour[:,:,0])
height = np.max(contour[:,:,1]) - np.min(contour[:,:,1])
block_area = width * heigh
contour_area = cv2.contourArea(contour)
slimier = cv2.contourArea(contour) / block_area
if slimier > self.simliar_rate:
return True
return False
pass_contours = []
for contour in contours:
if screent_contour(contour):
pass_contours.append(contour)
3. OpenCV 与矩阵
OpenCV 是如何实现以上这些操作的呢?
3.1 图像读取
OpenCV 在读取图像的时候是将图像信息转换成了矩阵,默认矩阵为(height,width,channel),channel 对应的是 B、G、R 通道,每个像素点的色彩由三个通道一起决定,和三元色的关系是一样的,B、G、R 的大小代表的是色调比例。
3.2 色调空间转换
色调空间的转换是将图像数据从一种示意关系变换到了另一种示意关系,比方 BGR 转换到 HSV 色彩空间是将本来的三原色表示法转换到了色调(H),饱和度(S),明度(V)表示法,每个 channel 所示意的含意产生了变动。
从信息的角度思考,摄像机将光照信息采集后转化成了数字的模式(图像矩阵),色彩空间的转换是将图像数据从一种示意办法变换到另一种示意办法,信息的转化也会引起信息的失落或者引入噪声,比方摄像机在采集光照信息的时候很容易采集到椒盐噪声,抛弃光照信息中的一些频段,清晰度升高等等,在做色调空间转换的时候也可能产生信息失落,比方从彩色图片转化到灰度图。深度学习中的图像检测、人脸识别就是要从这些图像信息中提取咱们想要的信息。
3.3 图像旋转的数学含意
在做图像几何变换的时候,咱们须要提供变换矩阵,矩阵是怎么实现这些操作的呢?
咱们晓得矩阵代表的就是一种空间映射,nxm 的矩阵(列向量线性无关)代表的是 n 维空间到 m 维空间的映射,如上图所示,第一个立方体所在的空间通过一个 3 ×3 的矩阵映射到了第二个立方体所在的空间,立方体的形态产生了变动,再比方第一个立方体所在的空间通过一个 3 ×2 的矩阵映射到了它的影子所在的空间,立方体被压缩成了一个立体。
立方体能够通过矩阵 (实数范畴) 映射成球体吗?因为其代表的是线性变换,所以是不能够的。
咱们在解决图像问题的时候要将信息从一个空间映射到另一个空间,因为问题的复杂性所以线性映射是满足不了要求的,这也就是为什么在深度学习中须要退出激活函数的起因。
4. OpenCV 与机器学习
从上一节的剖析中咱们发现,图像的处理过程就是从数据中找法则,将图像信息从一种示意变换到另一种示意,这个工作正好是机器学习的强项,再延申一下,不论是图像数据、文本数据、音频数据,要从数据中找法则,都会用到机器学习,从信息的角度思考,这些问题实质上是没有区别的。
openCV 曾经集成了很多机器学习算法、如 K 近邻(KNN),反对向量机(SVM)、决策树、随机森林、Boost、逻辑回归、ANN 等。
下图是摘自 scikit-learn 的一张图片,很形象的展现了不同的机器学习算法是如何对数据进行解决的,从宏观角度来讲就是如何将信息变换到不同的空间。
5. 视频书籍举荐
篇幅限度,还有很多乏味的货色,没方法一一列举,举荐一些视频和书籍,供细细品味。
5.1 线性代数
3blue1brown《线性代数的实质》系列视频通过形象图像的动画直观的解释了线性代数的魔力,还有其它系列也很棒。
《程序员的数学 3 线性代数》也是一本很不错的线性代数教材,细细读完,受益匪浅。
5.2 概率论
《程序员的数学 2 概率统计》很零碎的解说了概率统计的常识,不是很了解线性代数的话,举荐先看线性代数。
5.3 OpenCV
《学习 OpenCV》是一本很不错的工具书。